无法对未安装的组件执行反应状态更新
Can’t perform a react state update on an unmounted component
要解决“警告:无法对未安装的组件执行 React 状态更新”,请isMounted
在挂钩中声明一个布尔值useEffect
,用于跟踪组件是否已安装。
组件的状态只应在组件已安装时更新。
应用程序.js
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 the component is mounted if (isMounted) { setState(result); } } fetchData(); return () => { // 👇️ when the component unmounts, set isMounted to false isMounted = false; }; }, []); return ( <div> <h2>State: {JSON.stringify(state)}</h2> </div> ); }; export default App;
当我们尝试更新未安装的组件的状态时,会导致警告“无法对未安装的组件执行 React 状态更新”。
消除警告的一种直接方法是isMounted
在我们的
useEffect挂钩中使用布尔值跟踪组件是否已安装。
应用程序.js
useEffect(() => { // 👇️ set isMounted to true let isMounted = true; async function fetchData() { const result = await Promise.resolve(['hello', 'world']); // 👇️ only update state if the component is mounted if (isMounted) { setState(result); } } fetchData(); return () => { // 👇️ when the component unmounts, set isMounted to false isMounted = false; }; }, []);
我们将isMounted
布尔值初始化为true
in useEffect
。
我们的fetchData
函数执行一项async
任务,最常见的是 API 请求,并根据响应更新状态。
isMounted
但是,请注意,如果变量设置为 ,我们只会更新状态true
。
应用程序.js
async function fetchData() { const result = await Promise.resolve(['hello', 'world']); // 👇️ only update state if the component is mounted if (isMounted) { setState(result); } }
这有助于我们避免警告,因为如果组件未安装,我们不会更新状态。
设置isMounted
为false
组件卸载时
useEffect
当组件卸载时,我们从钩子返回的函数被调用。
应用程序.js
return () => { // 👇️ when component unmounts, set isMounted to false isMounted = false; };
我们将isMounted
变量设置为false
表示组件不再挂载。
如果在组件卸载fetchData
后调用我们的函数
,则该块将不会运行,因为设置为。if
isMounted
false
应用程序.js
async function fetchData() { const result = await Promise.resolve(['hello', 'world']); // 👇️ only update state if component is mounted if (isMounted) { setState(result); } }
将逻辑提取到可重用的钩子中
如果你经常这样做,你可以将逻辑提取到一个可重用的钩子中。
应用程序.js
import {useState, useEffect, useRef} from 'react'; // 👇️ extract logic into a 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 the 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
属性被初始化为传递的参数。
应用程序.js
function useIsMounted() { const isMounted = useRef(false); useEffect(() => { isMounted.current = true; return () => { isMounted.current = false; }; }); return isMounted; }
我们跟踪组件是否挂载在我们的useIsMounted
挂钩中,就像我们直接在组件的useEffect
挂钩中所做的那样。
请注意,在我们的fetchData
函数中,我们必须检查 的值,
isMountedRef.current
因为current
ref 上的属性是 ref 的实际值。
应用程序.js
async function fetchData() { const result = await Promise.resolve(['hello', 'world']); // 👇️ only update state if the component is mounted if (isMountedRef.current) { setState(result); } }
额外资源
您可以通过查看以下教程来了解有关相关主题的更多信息: