发布于 2026-01-06 2 阅读
0

React Hook - 清理 useEffect

React Hook - 清理 useEffect

来源:https://wareboss.com/react-hook-clean-up-useeffect/

上一篇文章我们学习了 useEffect 中的异步操作及其正确用法(React Hook - useEffect 中的异步函数)。

今天我们将学习如何使用useEffect React Hook的清理功能

当您从已卸载的组件更新状态时,React 将抛出以下错误:

“无法对已卸载的组件执行 React 状态更新。此操作不会产生任何效果,但表明您的应用程序存在内存泄漏。要解决此问题,请在componentWillUnmount方法中取消所有订阅和异步任务。”

useEffect(() => {
    //Do all the job, for example, subscribe a websocket channel
    return function(){
        //Unsubscribe websocket channel
    };
}, []);
Enter fullscreen mode Exit fullscreen mode

阻止对已卸载的组件进行更新:

在这里您将学习如何预防这个问题

  useEffect(() => {
    let isCancelled = false;
    const runAsync = async () => {
      try {
        if (!isCancelled) {
          // do the job
        }
      } catch (e) {
        if (!isCancelled) {
          throw e;
        }
      }
    };

    runAsync();

    return () => {
      isCancelled = true;
    };
  }, [...]);
Enter fullscreen mode Exit fullscreen mode

与 setInterval/setTimeout 一起使用:

这是中止setInterval/setTimeout的一个不错解决方案:

useEffect(() => {
  const interval = setInterval(() => {
    console.log('Five Seconds!');
  }, 5000);
  return () => clearInterval(interval);
}, []);
Enter fullscreen mode Exit fullscreen mode

想象一下这样的使用场景:你打开了这个组件,然后又关闭了它。
如果不进行清理,setInterval 回调函数会继续运行。


与 Firestore 实时数据库配合使用:

这在使用Firestore 实时数据库时非常有用

useEffect(() => {
    //Subscribe: firebase channel
    const cleanUp = firebase.firestore().collection('photos') .doc(id)
        .onSnapshot( doc => {
            setLoading(false);
            setPhotos(doc)
        }, err => { setError(err); }
    );
    return () => cleanUp(); //Unsubscribe
 }, []);
Enter fullscreen mode Exit fullscreen mode

如果您忘记清理您的 Firestore 订阅,您可能会收到不必要的请求。


与 fetch + AbortController 一起使用:

使用fetch/es6中的AbortController取消 fetch

  useEffect(() => {
    const abortController = new AbortController();
    const fetchData = async () => {
      try {
        const ret = await fetch("/companies", { signal: abortController.signal });
        const data = await ret.json();
        // ...
      }
      catch(error) {
        if (abortController.signal.aborted) {
          // cancelled
        }
        else
          throw error;
      };
    };

    fetchData();

    return () => abortController.abort();
  }, [companies]);
Enter fullscreen mode Exit fullscreen mode

使用 axios 请求:

以下是如何使用 axios 取消请求。

useEffect(() => {
  const source = axios.CancelToken.source();

  const fetchData = async () => {
    try {
      const response = await Axios.get("/companies", {
        cancelToken: source.token
      });
      // ...
    } catch (error) {
      if (Axios.isCancel(error)) {
        //cancelled
      } else {
        throw error;
      }
    }
  };

  fetchData()

  return () => {
    source.cancel();
  };
}, [companies]);

useEffect函数相当于React 类组件中的componentDidMount函数。

清理函数相当于React 类组件中的componentWillUnmount 函数

下一篇文章:React 类组件React 函数组件的区别。

再见!

文章来源:https://dev.to/iquirino/react-hook-clean-up-useeffect-24e7