为什么每次渲染都会调用来自 `useEffect` 的清理函数?

Joj*_*oji 40 javascript reactjs react-hooks use-effect

我一直在学习 React,我读到从返回的函数useEffect是为了进行清理,而 React 在组件卸载时执行清理。

因此,我对其进行了一些试验,但在以下示例中发现,每次组件重新渲染时都会调用该函数,而不是仅在从 DOM 卸载时调用该函数,即每次组件重新渲染时都会调用该函数console.log("unmount");

这是为什么?

function Something({ setShow }) {
  const [array, setArray] = useState([]);
  const myRef = useRef(null);

  useEffect(() => {
    const id = setInterval(() => {
      setArray(array.concat("hello"));
    }, 3000);
    myRef.current = id;
    return () => {
      console.log("unmount");
      clearInterval(myRef.current);
    };
  }, [array]);

  const unmount = () => {
    setShow(false);
  };

  return (
    <div>
      {array.map((item, index) => {
        return (
          <p key={index}>
            {Array(index + 1)
              .fill(item)
              .join("")}
          </p>
        );
      })}
      <button onClick={() => unmount()}>close</button>
    </div>
  );
}

function App() {
  const [show, setShow] = useState(true);

  return show ? <Something setShow={setShow} /> : null;
}
Run Code Online (Sandbox Code Playgroud)

实例:https : //codesandbox.io/s/vigilant-leavitt-z1jd2

Avi*_*ish 49

当组件卸载时,React 执行清理。

我不确定你在哪里读到的,但这个说法是不正确的。当对该钩子的依赖关系发生变化并且效果钩子需要使用新值再次运行时,React 会执行清理。此行为是有意保持视图对更改数据的反应性。离开官方示例,假设一个应用程序从朋友的个人资料中订阅状态更新。作为您的好朋友,您决定与他们成为朋友并与其他人成为朋友。现在该应用程序需要取消订阅前一个朋友的状态更新并听取新朋友的更新。这很自然,也很容易通过useEffect工作方式实现。

 useEffect(() => { 
    chatAPI.subscribe(props.friend.id);

    return () => chatAPI.unsubscribe(props.friend.id);
  }, [ props.friend.id ])
Run Code Online (Sandbox Code Playgroud)

通过在依赖列表中包含好友 id,我们可以指示只有在好友 id 更改时才需要运行钩子。

在您的示例中,您已array在依赖项列表中指定了,并且您正在以设定的时间间隔更改数组。每次更改数组时,钩子都会重新运行。

您可以通过从依赖项列表中删除数组并使用setState钩子的回调版本来实现正确的功能。回调版本总是对上一版本的状态进行操作,因此不需要每次数组变化时都刷新钩子。

  useEffect(() => {
    const id = setInterval(() => setArray(array => [ ...array, "hello" ]), 3000);

    return () => {
      console.log("unmount");
      clearInterval(id);
    };
  }, []);
Run Code Online (Sandbox Code Playgroud)

一些额外的反馈是直接使用 id ,clearInterval因为当您创建清理函数时关闭(捕获)该值。无需将其保存到 ref。

  • 引用“React 在组件卸载时执行清理”。直接来自 React:https://reactjs.org/docs/hooks-effect.html (14认同)
  • 必须对此投反对票,因为您引用的声明没有错误,只是不完整。而且它来自官方文档,因此暗示他们读错了东西是没有帮助的。 (5认同)
  • 来自 React:“React 在组件卸载时执行清理。但是,正如我们之前了解到的,效果会针对每个渲染运行,而不仅仅是一次。这就是为什么 React 还会在下次运行效果之前清理上一个渲染的效果。 ” (4认同)
  • 继续阅读下去,您会发现这不仅仅是在组件卸载时发生。这就是我要表达的观点。 (3认同)