正文从这开始~
总览
为了解决"Warning: Can't perform a React state update on an unmounted component"
,可以在你的useEffect
钩子中声明一个isMounted
布尔值,用来跟踪组件是否被安装。一个组件的状态只有在该组件被挂载时才会被更新。
import {useState, useEffect} from 'react'; const App = () => { const [state, setState] = useState(''); useEffect(() => { // 👇️ set isMounted to true let isMounted = true; async function fetchData() { const result = await Promise.resolve(['hello', 'world']); // 👇️ only update state if component is mounted if (isMounted) { setState(result); } } fetchData(); return () => { // 👇️ when component unmounts, set isMounted to false isMounted = false; }; }, []); return ( <div> <h2>State: {JSON.stringify(state)}</h2> </div> ); }; export default App;
当我们试图更新一个未挂载的组件的状态时,会出现"无法在未挂载的组件上执行React状态更新"的警告。
isMounted
摆脱该警告的直截了当的方式是,在useEffect
钩子中使用isMounted
布尔值来跟踪组件是否被挂载。
在useEffect
中,我们初始化isMounted
布尔值为true
。
我们的fetchData
函数执行一些异步的任务,最常见的是一个API请求,并根据响应来更新状态。
然而,需要注意的是,我们只有当isMounted
变量被设置为true
时,才会更新状态。
async function fetchData() { const result = await Promise.resolve(['hello', 'world']); // 👇️ only update state if component is mounted if (isMounted) { setState(result); } }
这可以帮助我们避免警告,因为如果组件没有挂载,我们就不会更新状态。
当组件卸载时,从useEffect
钩子返回的函数会被调用。
return () => { // 👇️ when component unmounts, set isMounted to false isMounted = false; };
我们设置isMounted
变量为false
,表示该组件不再挂载。如果fetchData
函数在组件卸载时被调用,if
代码块不会执行是因为isMounted
设置为false
。
async function fetchData() { const result = await Promise.resolve(['hello', 'world']); // 👇️ only update state if component is mounted if (isMounted) { setState(result); } }
提取
如果经常这样做,可以将逻辑提取到可重用的钩子中。
import {useState, useEffect, useRef} from 'react'; // 👇️ extract logic into reusable hook function useIsMounted() { const isMounted = useRef(false); useEffect(() => { isMounted.current = true; return () => { isMounted.current = false; }; }); return isMounted; } const App = () => { const [state, setState] = useState(''); // 👇️ use hook const isMountedRef = useIsMounted(); useEffect(() => { async function fetchData() { const result = await Promise.resolve(['hello', 'world']); // 👇️ only update state if component is mounted if (isMountedRef.current) { setState(result); } } fetchData(); }, [isMountedRef]); return ( <div> <h2>State: {JSON.stringify(state)}</h2> </div> ); }; export default App;
useRef()
钩子可以传递一个初始值作为参数。该钩子返回一个可变的ref对象,其.current
属性被初始化为传递的参数。
我们在useIsMounted
钩子中跟踪组件是否被挂载,就像我们直接在组件的useEffect
钩子中做的那样。
需要注意的是,在fetchData
函数中,我们必须检查isMountedRef.current
的值,因为ref
上的current
属性是ref
的实际值。