每次输入都会导致每次输出量增加一倍,导致在几次输入后陷入长循环. 这是密码

  const [direction,setDirection] = useState(Array(1).fill(0));
  const directions = ["botNorth","botEast","botSouth","botWest"];
  const [squares, setSquares] = useState(Array(5).fill().map(()=> Array(5).fill(null)));

  useEffect(()=> {
    const handleKeyDown = (e) =>{
      e = e || window.event;
      const nextSquares = squares.slice();
      var nextDirection = direction.slice();
      console.log(e.which);
      if (e.keyCode == '38') {
          // up arrow
      }
      else if (e.keyCode == '37') {
         // left arrow
         nextDirection[0]--;
         if (nextDirection[0] < 0) {
          nextDirection[0] = 3;
         }

      }
      else if (e.keyCode == '39') {
         // right arrow
      }
      setDirection(nextDirection);
      nextSquares[location[0]][location[1]] = <img className={directions[nextDirection[0]]} src={bot}/>;
      setSquares(nextSquares);
    return () => document.removeEventListener('keydown', handleKeyDown);
    };
    document.addEventListener('keydown', handleKeyDown, true);
});

this is the resulting error each key was only pressed once screenshot of error

我try 在功能内部和外部移动添加和删除收听者,但这似乎没有什么区别 当我注释掉setSquare()setDirection()时,它每个输入输出两次,而不是每次加倍

推荐答案

需要知道的一件事是,由于您在添加事件监听器时设置了选项,因此在删除事件监听器时也需要相同的选项. 所以document.addEventListener('keydown', handleKeyDown, true);需要document.removeEventListener('keydown', handleKeyDown, true);否则清理函数看起来是正确的. 抱歉这里说错了,清理工作需要移出handleKeyDown. useEffect需要返回清理功能.

我还会用这些参数setDirection, setSquares, squares, direction向您的useEffect添加一个依赖项array.这将限制每次渲染时激发的使用效果,并且仅在squaresdirection改变值时才会激发

  useEffect(()=> {
    const handleKeyDown = (e) =>{
      e = e || window.event;
      const nextSquares = squares.slice();
      var nextDirection = direction.slice();
      console.log(e.which);
      if (e.keyCode == '38') {
          // up arrow
      }
      else if (e.keyCode == '37') {
         // left arrow
         nextDirection[0]--;
         if (nextDirection[0] < 0) {
          nextDirection[0] = 3;
         }

      }
      else if (e.keyCode == '39') {
         // right arrow
      }
      setDirection(nextDirection);
      nextSquares[location[0]][location[1]] = <img className={directions[nextDirection[0]]} src={bot}/>;
      setSquares(nextSquares);

    };
    document.addEventListener('keydown', handleKeyDown, true);
    return () => document.removeEventListener('keydown', handleKeyDown, true);
}[setDirection, setSquares, squares, direction]);

对useEffect的更新应该会让您基本上达到这个目标. 我仍然偶尔会看到重复的事件. 我觉得每次状态更改时添加和删除事件监听器可能不是最好的方法.我只会在第一个渲染上添加事件监听器,而不会在事件监听器中读取状态. 我会使用Refs,我可以直接从事件监听器中变异,然后使用callBack来通知reaction状态已更改.

Javascript相关问答推荐

vue3类型脚本中可能未定义对象''

Express.js:以块形式发送响应

调用SEARCH函数后,程序不会结束

为什么getRecord()会因为与_logger相关的错误而失败?(使用Hedera SDK)

在分区内迭代分区

有什么(最佳)方法可以从模块中获取脚本模块的多姆元素吗?

Redux工具包查询(RTKQ)端点无效并重新验证多次触发

if/else JavaScript中的条件行为

使用续集和下拉栏显示模型属性

yarn安装一个本地npm包,以便本地包使用main项目的node_modules(ckeditor-duplicated-modules错误)

useNavigation更改URL,但不呈现或显示组件

无法在nextjs应用程序中通过id从mongoDB删除'

Angular material 拖放堆叠的牌副,悬停时自动展开&

html + java script!需要帮助来了解为什么我得到(无效的用户名或密码)

我可以使用使用node.js创建的本地主机来存储我网站上提交的所有数据吗?没有SQL或任何数据库.只有HTML语言

如何在文本字段中输入变量?

JavaScript是否有多个`unfined`?

用于测试其方法和构造函数的导出/导入类

如何让SVG图标在被点击和访问后改变 colored颜色 ,并在被访问后取消点击时恢复到原来的 colored颜色 ?

为什么我的SoupRequest";被重置为初始值,以及如何修复它?