Esta es una pregunta de novato para react-redux. Pasé un par de horas buscando antes de encontrarla, así que publicaré la pregunta y luego la responderé para la posteridad y también quizás la revisión del código.
Estoy usando react-redux para crear un juego en el que quiero usar las teclas WASD para mover un personaje por un mapa pequeño. (Este es solo un ejemplo de práctica para un esfuerzo mayor). El mapa consiste simplemente en un montón de <div> de colores.
Según tengo entendido, necesito vincular de alguna manera el evento de pulsación de tecla a algo en React DOM para activar mapDispatchToProps y luego iniciar la reevaluación de los reductores. El problema es que, al ser una pulsación de tecla, no hay nada a lo que vincularse. Estoy usando jquery para vincular la pulsación de tecla y llamar a la función.
Consultas relacionadas:
Básicamente, puede desencadenar una acción en un controlador de eventos de keypress de tecla
class App extends React.Component { constructor() { super(); this.handleKeyPress = this.handleKeyPress.bind(this); } handleKeyPress(event) { // you may also add a filter here to skip keys, that do not have an effect for your app this.props.keyPressAction(event.keyCode); } componentDidMount() { document.addEventListener('keypress', this.handleKeyPress); } componentWillUnmount() { document.removeEventListener('keypress', this.handleKeyPress); } render() { return <div>Your game content</div>; } } export default connect(mapStateToProps, {keyPressAction})(App) handleKeyPress llama al creador de la acción, que empujará la acción a los reductores.
Para aquellos que usan redux más nuevos en mecanografiado con clases funcionales, probablemente quieran algo como esto:
import { useDispatch } from "react-redux"; import { useEffect } from "react"; const App = () => { const dispatch = useDispatch(); useEffect(() => { document.addEventListener('keydown', handleKeyDown); document.addEventListener('keyup', handleKeyUp); return function cleanup() { document.removeEventListener('keydown', handleKeyDown); document.removeEventListener('keyup', handleKeyUp); }; }); const handleKeyDown = (event) => { console.debug("Key event", event); dispatch(handleKeyInput(game_state, connection_status, event.key)); document.removeEventListener('keydown', handleKeyDown); }; const handleKeyUp = (event) => { document.addEventListener('keydown', handleKeyDown, {once: true}); }; }Consulte https://reactjs.org/docs/hooks-effect.html .
La solución fue adaptada de aquí:
addEventListener reacciona redux con despacho mapeado
la clave es soltar el jquery y vincularlo DENTRO del componente de reacción usando document.addEventListener. aquí está el extracto del código de trabajo:
//////////////////////////////////////////// ////////////////////// containers //////////////////////////////////////////// class GameMap extends React.Component{ renderMap(){ console.log('renderMap') console.log(this.props) return this.props.gamemap.map((tile) => { //const x = "tile " + tile return <div className={"tile " + tile}></div> }) } render() { console.log('GameMap.render()') return ( <div className="GameMap"> {this.renderMap()} </div>) } componentDidMount() { console.log("componentDidMount") console.log(this) // the following line won't be bound to the store here... document.addEventListener("keydown", this.props.keyPress ); } } function GMmapStateToProps(state){ //from here goes into this.props console.log('BLmapStateToProps') console.log(state) const gamemap = state.gamemap.gamemap.map((a) => { switch (a){ case 1: return "tile-free" case 9: return "tile-user" } return "tile-wall" }) return{ gamemap: gamemap } } function GMmapDispatchToProps(dispatch){ //when selectbook called, pass result to all reducers console.log('GMmapDispatchToProps') return bindActionCreators({keyPress: keyPress}, dispatch) } const VGameMap = connect(GMmapStateToProps, GMmapDispatchToProps)(GameMap) //////////////////////////////////////////// ////////////////////// actions //////////////////////////////////////////// // actions/index.js action creator function keyPress(key) { console.log('keyPress: ', key) console.log(key.key) var vector = "" switch(key){ case 'w', 'ArrowUp': vector = {x:0,y:1} case 's', 'ArrowDown': vector = {x:0,y:-1} case 'a', 'ArrowLeft': vector = {x:-1,y:0} case 'd', 'ArrowRight': vector = {x:1,y:0} } return { type: "KEYPRESS", payload: vector } // this is an action created }