首页 > 解决方案 > 如何使用反应钩子清理 useEffect 中的 setInterval

问题描述

我正在尝试创建一个加载组件,该组件将使用 React 中的 setInterval 每 1000 毫秒定期向 div 添加一个句点。我正在尝试使用文档中描述的方法清理 setInterval。

https://reactjs.org/docs/hooks-effect.html#example-using-hooks-1

import React, { useEffect, useState } from 'react'

const Loading = () => {
    const [loadingStatus, setLoadingStatus] = useState('.')
    const [loop, setLoop] = useState()
    useEffect(() => {
        setLoop(setInterval(() => {
            console.log("loading")
            setLoadingStatus(loadingStatus + ".")
        }, 1000))

        return function cleanup() {
            console.log('cleaning up')
            clearInterval(loop)
        }
    }, [])
    return (<p>
        {`Loading ${loadingStatus}`}
    </p>)
}
export default Loading

但是,loadingStatus 变量只更新一次,即使在组件停止安装后 setInterval 循环也不会被清除。我必须使用类组件来实现吗?

标签: javascriptreactjsreact-hooks

解决方案


依赖项是我们对 React 何时应该运行效果的提示,即使我们设置了一个时间间隔并且没有提供依赖项[],React 也不会知道我们想要多次运行它,因为在我们的空依赖项中没有任何真正的变化[]

为了得到想要的结果,我们需要考虑什么时候要运行效果?

我们希望在loadingStatus更改时运行它,因此我们需要添加loadingStatus为我们的依赖项,因为我们希望在每次loadingStatus更改时运行效果。

我们有 2 个选择

添加loadingStatus为我们的依赖项。

const Loading = () => {
  const [loadingStatus, setLoadingStatus] = useState(".");
  const [loop, setLoop] = useState();

  useEffect(
    () => {
      setLoop(
        setInterval(() => {
          console.log("loading");
          setLoadingStatus(loadingStatus + ".");
        }, 1000)
      );

      return function cleanup() {
        console.log("cleaning up");
        clearInterval(loop);
      };
    },
    [loadingStatus]
  );

  return <p>{`Loading ${loadingStatus}`}</p>;
};

让我们的效果不知道我们使用loadingStatus

const Loading = () => {
  const [loadingStatus, setLoadingStatus] = useState(".");

  useEffect(() => {
    const intervalId = setInterval(() => {
      setLoadingStatus(ls => ls + ".");
    }, 1000);

    return () => clearInterval(intervalId);
  }, []);

  return <p>{`Loading ${loadingStatus}`}</p>;
};

在这里阅读更多 =>一个完整的使用指南


推荐阅读