【问题标题】:How to solve "can't perform a react state update on an unmounted component"如何解决“无法对未安装的组件执行反应状态更新”
【发布时间】:2021-01-09 08:38:29
【问题描述】:

无法对未安装的组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏。要解决此问题,请在 useEffect 清理函数中取消所有订阅和异步任务。 在 PokemonListItem(在 PokemonList.jsx:148)

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

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

口袋妖怪列表项

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...

口袋妖怪列表

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

【问题讨论】:

    标签: javascript reactjs react-native


    【解决方案1】:

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

       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;
        }
      }, []);
    

    【讨论】:

    • bug 依然存在。
    【解决方案2】:

    试试这个

    React.useEffect(() => {
     (async function onMount() {
       await fetch(url)
          .then((res) => res.json())
          .then((data) => setData(data));
    
        setReady(true);
     })();
    }, []);

    【讨论】:

    • 这正是他所拥有的,您刚刚将getData 函数移到了效果范围内
    【解决方案3】:

    与前面提到的类似,关键是将状态更新 setReady() 包装在 if (mounted){} 块中。

    1. 创建局部变量来表示您的初始挂载状态let mounted = true; 在您的效果中具有异步调用
    2. 使用清理效果https://reactjs.org/docs/hooks-reference.html#cleaning-up-an-effect 将mounted 设置为false return () =&gt; { mounted = false }
    3. if (mounted) { setState(...)} 包装setState 调用
    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;}
    })
    

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

    如果您删除|| true 调用并刷新,您会看到内存泄漏错误消失了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-17
      • 1970-01-01
      • 2019-10-19
      • 1970-01-01
      • 2020-08-02
      • 2021-12-31
      • 2019-11-09
      相关资源
      最近更新 更多