Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

251
Vistas
React-Redux: What is the canonical way to bind a keypress action to kick off a reducer sequence?

This is a newbie question for react-redux I spent a couple hours hunting around before finding so I am posting the question and then answering for posterity and also maybe code review.

I am using react-redux to create a game where I want to use the WASD keys to move a character around a small map. (This is just a practice example for a larger endeavor). The map simply consists of a bunch of colored <div>s.

As I understand it I need to somehow bind the keypress event to something in the React DOM in order to trigger mapDispatchToProps and then kick off the reevaluation of the reducers. The problem is, this being a keypress, there is nothing to bind to. I am using jquery to bind the keypress and call the function.

Related queries:

  • React - detect 'enter' key press in change event this one isn't helpful because it just binds to the onChange event of a text area
  • https://facebook.github.io/react/docs/events.html#keyboard-events doesn't tell you how to bind and in fact I really couldnt figure out how to use onKeyDown at all with a element! weird.
over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

You can basically trigger an action in a keypress event handler

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 calls the action creator, that will push action down to reducers.

over 4 years ago · Santiago Trujillo Denunciar

0

For those using newer redux in typescript with functional classes, you probably want something like this:

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});
  };
}

See https://reactjs.org/docs/hooks-effect.html.

over 4 years ago · Santiago Trujillo Denunciar

0

solution was adapted from here:

addEventListener react redux with mapped dispatch

the key is to drop the jquery and to bind it WITHIN the react component using document.addEventListener. here is the excerpt of the working code:

////////////////////////////////////////////
////////////////////// 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
}
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda