多次调用useEffect或不访问更新的变量如何设置对useEffect的正确依赖关系?

问题描述

我正在尝试在keydown事件上添加一些行为,但是useEffect无法正常工作。

代码如下:

const Test = ({}) => {
  const [value,setValue] = React.useState(0);
  
    const add= (sum) => {
    setValue(value+sum);
  }
  
  React.useEffect(()=> {
    const handleKeyDown = (e: KeyboardEvent) => {
      console.log("keypress",value);
      if (e.key === 'ArrowLeft') {
        add(-1);
      } else if (e.key === 'ArrowRight') {
        add(1);
      }
    }
    document.addEventListener('keydown',event => handleKeyDown(event));
    return () => {
      console.log("remove event")
      document.removeEventListener('keydown',event => handleKeyDown(event));
    };
  },[add])
  
  return <span>Count {value}</span>

}

Here is jsfiddle code-您可以在控制台上的按键上看到它多次调用。

如果将空数组放在useEffect依赖项上,则在调用add函数时,该值将始终为0。如果将add或value放在依赖项数组上,则每按一次useEffect键都会触发多次。有解决方案吗?

解决方法

通过将内联箭头函数传递给addEventListener,您每次都创建一个新的处理程序,而删除该处理程序将不起作用,因为再次声明要删除的新函数-该函数从来没有添加过:

// creates a new handler function every time
document.addEventListener('keydown',event => handleKeyDown(event));

// removing a function that isn't currently registered as a
// listener on the document,because it's a brand new inline function.
document.removeEventListener('keydown',event => handleKeyDown(event)); 

每次渲染时都会添加另一个keydown侦听器实例,并且永远不会删除它们,因此当您与应用交互时,它们会堆积。

无需创建新函数即可仅调用现有函数。尝试以下方法:

document.addEventListener('keydown',handleKeyDown);
return () => document.removeEventListener('keydown',handleKeyDown);

您的add函数存在类似问题。将add声明为效果依赖项会导致效果每次运行,因为add会在每个渲染器上重新声明。将其包装在useCallback中,以防止每次都重新创建它:

const add = React.useCallback((sum) => {
  setValue(value+sum);
},[value]);

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...