React报错之无法在未挂载的组件上执行React状态更新

正文从这开始~

总览

为了解决"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的实际值。

发表评论

相关文章