在 React 应用程序中我们遇到以下警告消息:
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 组件就会导致内存泄漏问题,比如:
- 用户执行触发事件处理程序以从 API 获取数据的操作。
- 然后,用户点击一个链接,在完成第 1 步之前导航到另一个页面。
- 此时,第1步操作完成并传递从 API 获取到的数据并调用setState。
由于组件已卸载,并且函数正在已经卸载的组件中调用,因此会导致内存泄漏问题——并且在控制台中,会出现上述警告。
错误代码示例:
const [value, setValue] = useState('checking value...');
useEffect(() => {
fetchValue().then(() => {
setValue("done!"); // ⚠️ what if the component is no longer mounted ?
// we got console warning of memory leak
});
}, []);
如何避免此类问题
1、 使用变量标记组件状态
const [value, setValue] = useState('checking value...');
useEffect(() => {
let isMounted = true;
fetchValue().then(() => {
if(isMounted ){
setValue("done!"); // no more error
}
});
return () => {
isMounted = false;
};
}, []);
在上面的代码中,创建了一个变量isMounted
,其初始值为true
。当isMounted
为true
时,更新状态并返回函数。否则,如果操作在完成之前被卸载,则函数isMounted以 false
返回。
2、使用 AbortController
useEffect(() => {
let abortController = new AbortController();
// your async action is here
return () => {
abortController.abort();
}
}, []);
- 在上述代码中,
AbortController
用来实现取消订阅效果。异步操作完成后,中止控制器取消订阅。
3、使用use-state-if-mounted Hook
const [value, setValue] = useStateIfMounted('checking value...');
useEffect(() => {
fetchValue().then(() => {
setValue("done!"); // no more error
});
}, []);
在上述代码中,使用了一个自定义的钩子 useStateIfMounted
,它的作用用来在更新状态之前检查组件是否已安装!
- component unmounted perform update Reactcomponent unmounted perform update application component indicates unmounted typescript component strongly react composable component context react typescript component generics react react typescript component strongly react typescript components propstype handlechange component function react component server react 项目react component不断