【问题标题】:Can't perform a React state update on an unmounted component - memory leak?无法对未安装的组件执行 React 状态更新 - 内存泄漏?
【发布时间】:2021-06-29 15:58:00
【问题描述】:

我曾尝试在useEffectreturn () => mounted.current = false 的开头使用mounted = useRef()let mounted.current = true,但我仍然收到此错误消息:

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
    in NameDetails (at TitleRow.js:114)
    in RCTView (at View.js:34)
    in View (at TitleRow.js:113)
    in titleRow (at TodayTitleList.js:154)
    in RCTView (at View.js:34)
    in View (at VirtualizedList.js:2015)
    in VirtualizedListCellContextProvider (at VirtualizedList.js:2030)
    in CellRenderer (at VirtualizedList.js:807)
    in RCTScrollContentView (at ScrollView.js:1107)
    in RCTScrollView (at ScrollView.js:1213)
    in ScrollView (at ScrollView.js:1264)
    in ScrollView (at VirtualizedList.js:1250)
    in VirtualizedListContextProvider (at VirtualizedList.js:1080)
    in VirtualizedList (at FlatList.js:620)
    in FlatList (at TodayTitleList.js:149)
    in RCTSafeAreaView (at SafeAreaView.js:51)
    in SafeAreaView (at TodayTitleList.js:136)

查看堆栈跟踪,我冒昧地猜测错误在 NameDetails 文件中,它涉及其中的 useEffect。是这样吗?

以下是我的代码:

const NameDetails = ({ title }) => {
  const [color, setColor] = useState('#000');

  useEffect(() => {
    //let mounted = true; 
    const getColor = async (id) => {
      const chosenColor = await getColorFortitle(id);
      setColor(chosenColor);
    //return () => { mounted = false };
    };

    getColor(title.id);
  });

  return (
    <View>
        ...
    </View>
  );
};

export default NameDetails;

更多信息:当我注销并尝试再次登录时会发生此错误,并且仅在某些时候发生。

【问题讨论】:

  • 您好,请问您有什么问题?你只想修复错误?还是其他?
  • 我想修复错误,是的,但也理解为什么设置布尔挂载不能解决问题。
  • 可以使用状态吗?
  • 请检查我的回答。
  • 你可以得到状态的值。然后使用它。怎么样?

标签: reactjs react-native use-effect


【解决方案1】:
const NameDetails = ({ title }) => {
  const [color, setColor] = useState('#000');

  useEffect(() => {
    let mounted = true; 
    
    const getColor = async (id) => {
      const chosenColor = await getColorFortitle(id);
      mounted && setColor(chosenColor);
    };

    getColor(title.id);

    return () => { mounted = false };
  }, [title.id]);

  return (
    <View>
        ...
    </View>
  );
};

更理想的方法:

const NameDetails = ({ title }) => {
  const isMounted = React.useRef(true);

  React.useEffect(() => () => (isMounted.current = false), []);
  
  const [color, setColor] = useState('#000');

  useEffect(() => {
    const getColor = async (id) => {
      const chosenColor = await getColorFortitle(id);
      isMounted.current && setColor(chosenColor);
    };

    getColor(title.id);
  }, [title.id]);

  return (
    <View>
        ...
    </View>
  );
};

或者,如果您不确定那里发生了什么,您可以尝试将我的库与基于生成器的异步钩子一起使用,您不必担心卸载:

import React, { useState } from "react";
import { useAsyncEffect } from "use-async-effect2";

const NameDetails = ({ title }) => {     
  const [color, setColor] = useState('#000');

  useAsyncEffect(function*(){
      const chosenColor = yield getColorFortitle(title.id);
      setColor(chosenColor);
  }, [title.id]);

  return (
    <View>
        ...
    </View>
  );
};

【讨论】:

  • 为什么没有依赖的 useEffect 调用是一种更理想的方法?每次渲染都会不必要地调用它。
  • @SomeoneSpecial 这只是一个复制/粘贴问题-作者的源代码中缺少它。当然,我们应该始终将依赖项传递给钩子。 “更理想” == 使用 useRef 定义 isMounted 变量,因为我们可以将它重用于组件内部使用的所有钩子,包括 useCallback
  • isMounted.current && setColor(chosenColor);
【解决方案2】:

请检查我的代码 希望对你有帮助。

const NameDetails = ({ title }) => {
  const [color, setColor] = useState('#000');
  const [mounted, setMount] = useState(true);

  useEffect(() => { 
    const getColor = async (id) => {
      const chosenColor = await getColorFortitle(id);
      setColor(chosenColor);
      return () => { setMount = false };
    };

    getColor(title.id);
  });

  return (
    <View>
        ...
    </View>
  );
};

export default NameDetails;

我只使用一种状态。因此,您可以使用状态更改值。 在您的代码上运行。

【讨论】:

【解决方案3】:

您正在使用useEffect 每次您的组件重新渲染: 添加empty dependency to useEffect to run only on first render

const mounted = useRef(false);

useEffect(() => mounted.current = true, []);


useEffect(() => {
    const getColor = async (id) => {
     const chosenColor = await getColorFortitle(id);
     setColor(chosenColor);
    }

    if(mounted.current)
      getColor(title.id);

    return () => { mounted.current = false };
}, []);

【讨论】:

  • 我不能使用await getColor(title.id);,因为 useEffect 不是异步的?
  • 是的,你不能。我的错。编辑后的答案现在看到
  • 现在检查,我忘了添加安装条件
  • 它不起作用,我仍然收到同样的警告。
  • 是的,我包含了if(mounted.current)
猜你喜欢
  • 2020-01-24
  • 2021-11-25
  • 1970-01-01
  • 2021-07-01
  • 2020-11-21
  • 2019-11-09
  • 2019-05-30
  • 2021-05-30
相关资源
最近更新 更多