React-Redux:绑定按键操作以启动减速器序列的规范方法是什么?

IT技术 reactjs redux react-redux
2021-05-01 22:41:24

这是 react-redux 的一个新手问题,我花了几个小时四处寻找才找到,所以我发布了这个问题,然后为后代回答,也可能是代码审查。

我正在使用 react-redux 创建一个游戏,我想使用 WASD 键在小地图上移动角色。(这只是更大努力的实践示例)。地图只是由一堆彩色的<div>s 组成。

据我了解,我需要以某种方式keypress事件绑定到 React DOM中的某些内容,以触​​发 mapDispatchToProps,然后开始重新评估减速器。问题是,这是一个按键,没有什么可以绑定的。我正在使用 jquery 绑定按键并调用该函数。

相关查询:

3个回答

您基本上可以在keypress事件处理程序中触发操作

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 调用动作创建者,它将动作下推到减速器。

对于那些在带有功能类的typescript中使用较新的 redux 的人,您可能需要这样的东西:

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

请参阅https://reactjs.org/docs/hooks-effect.html

解决方案是从这里改编的:

addEventListener 使用映射调度对 redux 做出react

关键是删除 jquery 并使用 document.addEventListener 将其绑定到 react 组件中。这是工作代码的摘录:

////////////////////////////////////////////
////////////////////// 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
}