无法对未安装的组件执行反应状态更新

无法对未安装的组件执行反应状态更新

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布尔值初始化为truein 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); } }

这有助于我们避免警告,因为如果组件未安装,我们不会更新状态。

设置isMountedfalse组件卸载时

useEffect当组件卸载时,我们从钩子返回的函数被调用。

应用程序.js
return () => { // 👇️ when component unmounts, set isMounted to false isMounted = false; };

我们将isMounted变量设置为false表示组件不再挂载。

如果在组件卸载fetchData后调用我们的函数
,则该块将不会运行,因为设置为
ifisMountedfalse

应用程序.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因为currentref 上的属性是 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); } }

额外资源

您可以通过查看以下教程来了解有关相关主题的更多信息: