reactjs - 如何阻止 useEffect hook React 中的内存泄漏

标签 reactjs react-table use-effect

我正在使用 Effect hook 从服务器获取数据,这些数据被传递到 react 表,我在那里使用相同的 api 调用从服务器加载下一组数据。 当应用程序加载时,我收到如下警告

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

效果 Hook :

useEffect(() => {
setPageLoading(true);
props
  .dispatch(fetchCourses())
  .then(() => {
    setPageLoading(false);
  })
  .catch((error: string) => {
    toast.error(error);
    setPageLoading(false);
  });
}, []);

react 表页面:

<ReactTable
  className="-striped -highlight"
  columns={columns}
  data={coursesData}
  defaultPage={currentPage}
  defaultPageSize={courses.perPage}
  loading={isLoading}
  manual={true}
  onFetchData={setFilter}
/>

设置过滤功能:

const setFilter = (pagination: any) => {
  props.dispatch(updateCoursePageSize(pagination.pageSize));
  props.dispatch(updateCourseCurrentPage(pagination.page + 1));
  setCurrentPage(pagination.page);
  setPerPage(pagination.pageSize);
  setLoading(true);
  props.dispatch(fetchCourses()).then(() => {
    setLoading(false);
  });
};

有谁知道如何清理react中的hook

最佳答案

更新(2022 年 6 月):

React 18 已删除此警告消息,并且可能不再需要消除它的解决方法。他们删除它的部分原因是它总是有点误导。它说你有内存泄漏,但很多时候你并没有。

问题中的代码(实际上是导致此警告的大多数代码)在组件卸载后运行有限的时间,然后设置状态,然后完成运行。由于运行完毕,javascript 可以释放其闭包中的变量,因此通常不会发生泄漏。

如果您正在设置无限期持续的持久订阅,则会出现内存泄漏。例如,也许您设置了一个 websocket 并监听消息,但您从未拆除该 websocket。这些情况确实需要修复(通过向 useEffect 提供清理函数),但它们并不常见。

React 18 删除警告的另一个原因是他们正在研究组件在卸载后保留其状态的能力。一旦该功能投入使用,卸载后设置状态将是完全有效的事情。

原始答案(2019 年 9 月):

使用 useEffect,您可以返回一个将在清理时运行的函数。因此,就您而言,您需要这样的东西:

useEffect(() => {
  let unmounted = false;

  setPageLoading(true);

  props
    .dispatch(fetchCourses())
    .then(() => {
      if (!unmounted) {
        setPageLoading(false);
      }
    })
    .catch((error: string) => {
      if (!unmounted) {
        toast.error(error);
        setPageLoading(false);
      }
    });

  return () => { unmounted = true };
}, []);

编辑:如果您需要在 useEffect 之外启动调用,那么它仍然需要检查未安装的变量以判断是否应该跳过对 setState 的调用。未安装的变量将由 useEffect 设置,但现在您需要克服一些障碍才能在效果之外访问该变量。

const Example = (props) => {
  const unmounted = useRef(false);
  useEffect(() => {
    return () => { unmounted.current = true }
  }, []);

  const setFilter = () => {
    // ...
    props.dispatch(fetchCourses()).then(() => {
      if (!unmounted.current) {
        setLoading(false);
      }
    })
  }

  // ...
  return (
    <ReactTable onFetchData={setFilter} /* other props omitted */ />
  );
}

关于reactjs - 如何阻止 useEffect hook React 中的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58038008/

相关文章:

reactjs - "[ts] Unterminated regular expression literal."

javascript - 使用来自 firebase 的数据填充 React-Table

javascript - 如何在React中的功能组件中制作与componentDidUpdate函数类似的函数?

javascript - 在 React 中解压 "this"是不好的做法吗?

javascript - React Semantic UI - 在下拉菜单中添加选项键

react 表版本 7 onSortedChange 回调等效

javascript - React 表出现问题 TypeError : Cannot read property 'forEach' of undefined

error-handling - react Hook 和异步等待: Handling errors with Axios call

reactjs - 无法在 useEffect Hook 内设置状态

reactjs - redux hooks : "could not find react-redux context value; please ensure the component is wrapped in a <Provider>" 的 enzyme 测试错误