如何解决“无法在未安装的组件上执行反应状态更新”

时间:2020-09-23 07:23:28

标签: javascript reactjs react-native

无法在已卸载的组件上执行React状态更新。这是空操作,但它表明应用程序中发生内存泄漏。要修复,请取消使用useEffect清理功能中的所有订阅和异步任务。 在PokemonListItem中(在PokemonList.jsx:148处)

好的,我知道这是一个常见问题,解决方案应该非常简单。我只是不知道如何在我的代码中实现它。

我正在使用React-Native和PokéAPI制作一种用于移动设备的Pokédex。我不确定泄漏在哪里,所以请有经验的开发人员提供帮助。

PokemonListItem

export default function PokemonListItem({ url, Favorite }) {
  const [pokemondata, setData] = React.useState({});
  const [dataReady, setReady] = React.useState(false);
  const [isFavorite, setFavorite] = React.useState(false);

  const favoriteStatus = (bool) => {
    setFavorite(bool);
  };

  const getData = async () => {
    await fetch(url)
      .then((res) => res.json())
      .then((data) => setData(data));

    setReady(true);
  };

  React.useEffect(() => {
    getData();
  }, []);

  more code...

PokemonList

const renderItem = ({ item }) => (
    <TouchableHighlight
      style={{ borderRadius: 10 }}
      underlayColor="#ffc3c2"
      onPress={() => {
        navigation.navigate("Pokémon Details", {
          url: item.url,
        });
      }}
    >
      <PokemonListItem url={item.url} Favorite={FavoriteButton} />
    </TouchableHighlight>
  );

如果需要查看完整的代码,可以访问repository

3 个答案:

答案 0 :(得分:0)

一种方法似乎是维护一个变量,以查看组件是否仍在安装中,这对我来说(React-hooks. Can't perform a React state update on an unmounted component)感觉很不舒服({{3}})-但是无论如何我会在您的代码中看到它...

   let isMounted;

   const getData = async () => {
     await fetch(url)
      .then((res) => res.json())
      .then((data) => { if(isMounted) setData(data)});

     setReady(true);
  };

  React.useEffect(() => {
    isMounted = true;
    getData();
    return () => {
      isMounted = false;
    }
  }, []);

答案 1 :(得分:0)

尝试一下

React.useEffect(() => {
 (async function onMount() {
   await fetch(url)
      .then((res) => res.json())
      .then((data) => setData(data));

    setReady(true);
 })();
}, []);

答案 2 :(得分:0)

类似于前面提到的,关键是将状态更新<div> <a class="menu-item"> <div class="icon"></div> <span>Example</span> </a> <a class="menu-item" style="font-variant: all-small-caps"> <div class="icon"></div> <span>Example</span> </a> </div>包装在setReady()块中。

  1. 创建局部变量以表示具有异步调用效果的初始安装状态if (mounted){}
  2. 使用清除效果https://reactjs.org/docs/hooks-reference.html#cleaning-up-an-effect设置为false let mounted = true;的挂载
  3. return () => { mounted = false }包裹setState调用
if (mounted) { setState(...)}

https://codesandbox.io/s/upbeat-easley-kl6fv?file=/src/App.tsx

如果删除useEffect(() => { let mounted = true; const apiRequest = async (setReady) => { let response; try { response = await APICall(); if (mounted) { setReady(response.data); } } catch (error) {} } apiRequest(); return () => { mounted = false;} }) 调用并刷新,则会发现内存泄漏错误消失了。