Reactjs 如何在useffect中阻止内存泄漏

Reactjs 如何在useffect中阻止内存泄漏,reactjs,react-table,use-effect,Reactjs,React Table,Use Effect,我使用effecthook从服务器获取数据,这些数据被传递到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 subscript

我使用effecthook从服务器获取数据,这些数据被传递到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.
效果挂钩:

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

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

是否有人知道如何使用react

和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 */ />
  );
}
const示例=(道具)=>{
const unmounted=useRef(false);
useffect(()=>{
return()=>{unmounted.current=true}
}, []);
常量setFilter=()=>{
// ...
props.dispatch(fetchCourses())。然后(()=>{
如果(!unmounted.current){
设置加载(假);
}
})
}
// ...
返回(
);
}

其他答案当然有效,我只是想分享我想出的一个解决方案。 我构建了一个类似React的useState的功能,但是只有在安装组件时才会设置state。我发现它更优雅,因为您不必在组件中乱用isMounted变量

安装: 用法:
const[count,setCount]=useStateIfMounted(0);

您可以在钩子的上找到更高级的文档。

但是如果在没有useEffect的情况下再次执行相同的API调用该怎么办。例如,如果API调用是useEffect,并且在函数中再次执行。@Nicholas Tower如果您看到setFilter函数,则会调用相同的调度调用fetchCourses()。如果两个调用同时发生,我将收到内存泄漏警告。如果我在setFilter函数中隐藏调用,那么就没有内存泄漏警告。该repo的作者说这不是一个可行的解决方案(只是隐藏了警告消息)。我也很沮丧,但只是想告诉大家。
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 */ />
  );
}
npm install use-state-if-mounted