乐趣区

关于react.js: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 的理论值。

退出移动版