在反应挂钩上设置事件处理程序(useEffect)

时间:2020-07-29 18:15:03

标签: reactjs react-hooks

当您按下一个键时,此组件始终警报0:(run it online

const Hello = () => {
  const [counter, setCounter] = React.useState(0)
  let canvas = React.useRef()
  let add = () => {
    setCounter(counter + 3)
    alert(counter)
  }
  React.useEffect(() => {
    window.onkeydown = add
  }, [])
  return <div><h1>{counter}</h1></div>
}

但是我的愿望输出是警告当前状态,而不是初始状态。

如果我将其更改为:

React.useEffect(() => {
    window.onkeydown = add
  })

工作正常(在每个渲染器上将add事件处理程序绑定到onkeydown。)

但是为什么它会这样呢? (我不想在每个渲染器上绑定事件处理程序,因为它似乎存在性能问题)

2 个答案:

答案 0 :(得分:2)

问题

仅在组件使用空的依赖项数组挂载时设置回调,从而将初始状态包含在附加的回调中。功能状态更新不会出现此问题,因为它使用回调函数来计算并从先前的状态值返回新的状态值。

解决方案

  • 效果需要正确添加事件侦听器。 (并返回清理功能!
  • 状态更新应该是功能更新,因为它取决于以前的状态。
  • 状态更新本质上是异步的,因此在入队后立即对其进行警报或记录只会记录 current 渲染周期中的 current 状态值。使用效果可对更新后的状态进行任何操作。

更新的代码

const Hello = () => {
  const [counter, setCounter] = React.useState(0);
  let canvas = React.useRef();

  const add = () => {
    setCounter(counter => counter + 3);
  };

  React.useEffect(() => {
    console.log(counter); // or alert, if you really want to
  }, [counter]);

  React.useEffect(() => {
    window.addEventListener("keydown", add);
    return () => window.removeEventListener("keydown", add);
  }, []);

  return (
    <div>
      <h1>{counter}</h1>
    </div>
  );
};

Edit Add window event listener

答案 1 :(得分:0)

传递空数组只会在安装组件时触发useEffect,只需在数组中添加计数器,以便每次状态更新时都触发它。

  React.useEffect(() => {
    window.onkeydown = add
  }, [counter])