来自在React.js UseEffect挂钩中创建的事件处理程序的访问状态

时间:2019-04-23 19:00:39

标签: reactjs react-hooks

在我的组件中,我正在useEffect钩子内设置事件监听器:

useEffect(() => {
  const target = subtitleEl.current;
  target.addEventListener("click", () => {
    console.log("click");
    onSubtitleClick();
  });

  return () => {
    target.removeEventListener("click", null);
  };
}, []);

..但是当我呼叫onSubtitleClick时,我的状态是陈旧的-这是原始值。 Example code here。如何从使用useEffect设置的事件处理程序中访问状态?

2 个答案:

答案 0 :(得分:1)

您的事件侦听器在定义的环境中注册一个count为0的函数(引用),并且当发生新的渲染时,您的引用未更新,该引用已在该元素和该注册的函数中注册即使计数已更改,参考也仍然知道count为0,但是未注册更新函数,该函数知道其上下文中的更新值。因此,您需要使用新的函数引用来更新事件侦听器。

useEffect(() => {
    const target = subtitleEl.current;
    target.addEventListener("click", onSubtitleClick);

    return () => {
      console.log("removeEventListener");
      target.removeEventListener("click", onSubtitleClick);
    };
}, [onSubtitleClick]);

但是,您不需要那些凌乱的代码即可实现您现在正在做的事情或类似的工作。您只需单击一下即可调用该传递的函数,而不必通过ref而是直接在jsx中附加到元素。

<div
    className="panelText"
    style={{ fontSize: "13px" }}
    onClick={onSubtitleClick}
    ref={subtitleEl}
  >
    Button2
</div>

答案 1 :(得分:0)

我认为基本上addeventlistener创建了一个闭包,其闭包的count版本与父组件的闭锁版本分开。一个简单的解决方法是允许useEffect函数在更改时重新运行(删除[] arg):

useEffect(() => {
  const target = subtitleEl.current;
  target.addEventListener("click", () => {
    console.log("click");
    onSubtitleClick();
  });

  return () => {
    target.removeEventListener("click", null);
  };
}); // removed [] arg which prevents useeffect being run twice