从 React.js UseEffect Hook 中创建的事件处理程序访问状态

Access state from Event Handler created within React.js UseEffect Hook

在我的组件中,我在 useEffect 挂钩中设置了一个事件侦听器:

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

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

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

您的事件侦听器注册了一个函数(引用),该函数(引用)在其定义的环境中具有 count 0,并且当发生新的渲染时,您的引用未更新,该引用已注册到该元素并且已注册的函数引用仍然知道计数为 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>

我认为基本上 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