【问题标题】:Use Effect Cleanup issue使用效果清理问题
【发布时间】:2022-11-24 19:59:48
【问题描述】:

以下代码用作 RN 应用程序中的离线监视器 - 它基本上用于在连接断开时显示警告。

  export default function InternetCheck() {
  const [isConnected, setIsConnected] = useState(false);
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    //Intial status

    NetInfo.fetch().then(state => {
      if (state.isInternetReachable == false) {
        setIsConnected(state.isInternetReachable);
      }
    });
    //Internet connection listener
    NetInfo.addEventListener(state => {
      setIsConnected(state.isInternetReachable);
    });
  }, []);

我在控制台中收到以下错误 -

警告:无法对未安装的组件执行 React 状态更新。 这是一个空操作,但它表明您的应用程序中存在内存泄漏。 要修复,取消 useEffect 中的所有订阅和异步任务 清理功能。

谁能解释一下如何在这种情况下应用清理功能?我已经阅读了其他各种问题,但无法理解逻辑方法。

【问题讨论】:

  • 看起来像是一个简单的清理,根据设计,它是您从此 useEffect 返回的函数(您的函数不返回任何内容)。在返回的函数中你应该...removeEventListener

标签: reactjs react-native


【解决方案1】:

正如 in the documentation 所说,您可以返回清理回调。您的回调应该删除事件侦听器。我在下面假设 NetInfo 有一个 removeEventListener 方法(因为它有一个 addEventListener 方法)。参见***cmets:

export default function InternetCheck() {
    const [isConnected, setIsConnected] = useState(false);
    const [mounted, setMounted] = useState(false);

    useEffect(() => {
        //Intial status
        NetInfo.fetch().then((state) => {
            if (state.isInternetReachable == false) {
                setIsConnected(state.isInternetReachable);
            }
        });

        //Internet connection listener
        const listener = (state) => {
            setIsConnected(state.isInternetReachable);
        };
        NetInfo.addEventListener(listener);
        return () => { // *** Return a cleanup callback
            NetInfo.removeEventListener(listener); // *** Remove the *same function* you added
        };
    }, []);

    // ...
}

请注意,重要的是(对于大多数这些添加/删除订阅)通过相同的功能用于添加和删除。这就是为什么我从 add 调用中提取函数表达式并将函数保存为常量的原因。

【讨论】:

    【解决方案2】:

    您好,您需要从 useEffect 函数中添加返回回调清理
    像这样:

         export default function InternetCheck() {
          const [isConnected, setIsConnected] = useState(false);
          const [mounted, setMounted] = useState(false);
        
          useEffect(() => {
            //Intial status
        
            NetInfo.fetch().then(state => {
              if (state.isInternetReachable == false) {
                setIsConnected(state.isInternetReachable);
              }
            });
            //Internet connection listener
            NetInfo.addEventListener(state => {
              setIsConnected(state.isInternetReachable);
            });
    //----> add the removeEventListener 
    return ()=>{
    NetInfo.removeEventListener(...)
    ......
    }
     }, []);
    

    【讨论】:

      【解决方案3】:

      您可以使用可变布尔变量来跟踪清理是否已针对您的渲染周期开始。如果有,则放弃更新(不再存在的状态)。这是一个例子:

      export default function InternetCheck () {
        const [isConnected, setIsConnected] = useState(false);
        const [mounted, setMounted] = useState(false);
      
        useEffect(() => {
          let cleanupStarted = false;
      
          //Intial status
      
          NetInfo.fetch().then(state => {
            if (state.isInternetReachable == false) {
              if (!cleanupStarted) setIsConnected(state.isInternetReachable);
            }
          });
      
          //Internet connection listener
          NetInfo.addEventListener(state => {
            if (!cleanupStarted) setIsConnected(state.isInternetReachable);
          });
      
          return () => void (cleanupStarted = true);
        }, []);
      }
      

      【讨论】:

      • 如果效果调用多次,看起来你最终可以得到多个事件监听器
      猜你喜欢
      • 1970-01-01
      • 2011-06-12
      • 2017-10-27
      • 1970-01-01
      • 2023-04-07
      • 1970-01-01
      • 2011-06-07
      • 2013-02-15
      • 2013-10-21
      相关资源
      最近更新 更多