React-防止内存泄漏处理
乔文飞 Lv8

用React写了一段代码,浏览器的控制台Error 如下:
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.

啥意思呢:不能在未挂载的组件上执行React状态更新。这是一个无用功,但它表明你的应用程序中存在内存泄漏。要解决这个问题,在useEffect清理函数中取消所有的订阅和异步任务。

以下是这段问题代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const Component = (props) => {
const { itemId } = props;
const [ isRemoveing, setIsRemoveing ] = useState(false);
const handlerRemove = async() => {
if(isRemoveing) return;
setIsRemoveing(true);
await removeItem(itemId); // 删除当前这个组件的数据,这个组件卸载
setIsRemoveing(false);
}
return (
<>
<div class_name={ !isRemoveing ? 'class1' : 'class2' } onClick={handlerRemove} ></div>
</>
)
}

原因是啥呢:await等待一个异步请求的返回再setIsRemoveing。假如这个组件unmounted之后,请求还没回来,你还在这setState,不就炸了。

好吧,那解决方式是不是在useEffect中定义一个卸载时的变量unmounted,然后在setIsRemoveing时判断卸载状态?

嗯,基本是这个思路。那这个unmounted该怎么定义,是直接const unmounted = false;, 还是const [ unmounted, setUnmounted ] = useState(false);
以下是Stack Overflow里一个帖子的回复:

  • 方式一:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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 };
    }, []);
  • 方式二:useRef
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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 */ />
    );
    }

方式二中如果不用ref,用state或者直接定义变量的话,都实现不了。
好吧,是我不熟悉的useRef,这个链接是官方文档,可以先看下。
然后为了研究它,我找到一篇来自Lee WarrickReact’s useEffect and useRef Explained for Mortals这里是我对这篇文章的翻译,仅供参考。

参考

React Hooks - Check If A Component Is Mounted
how-to-stop-memory-leak-in-useeffect-hook-react

  • 本文标题:React-防止内存泄漏处理
  • 本文作者:乔文飞
  • 创建时间:2021-06-18 13:40:49
  • 本文链接:http://www.feidom.com/2021/06/18/React-防止内存泄漏处理/
  • 版权声明:本博客所有文章为作者学习笔记,有转载其他前端大佬的文章。转载时请注明出处。