You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native卸载组件状态更新警告问题求助

解决React组件卸载后状态更新的内存泄漏问题

问题根源

你当前代码里的isMounted逻辑存在漏洞:getRooms和getLobbies函数虽然定义了清理函数(返回() => { isMounted = false }),但这些清理函数从未被执行。每次调用这两个函数时,仅触发了异步请求,却没有保存并调用清理逻辑。当组件卸载后,未完成的请求仍会在结束后尝试更新状态,最终触发内存泄漏警告。

另外,现有代码仅清理了定时器,但未处理每个异步请求自身的取消逻辑。


推荐解决方案:使用AbortController取消请求

该方案不仅能阻止状态更新,还能直接中断未完成的网络请求,节省资源,是React官方推荐的异步请求清理方式。

修正后代码

import { useState, useEffect } from 'react';

// 组件内部逻辑
const [isLoadingRoom, setLoadingRoom] = useState(true);
const [isLoadingLobby, setLoadingLobby] = useState(true);
const [rooms, setRooms] = useState([]);
const [lobbies, setLobbies] = useState([]);

// 获取房间数据:接收AbortSignal参数
const fetchRooms = async (signal) => {
  try {
    const response = await fetch(link, { signal });
    const json = await response.json();
    setRooms(json);
    setLoadingRoom(false);
  } catch (error) {
    // 忽略请求被取消的错误
    if (error.name !== 'AbortError') {
      console.error('获取房间数据失败:', error);
      setLoadingRoom(false);
    }
  }
};

// 获取大厅数据:同理接收AbortSignal参数
const fetchLobbies = async (signal) => {
  try {
    const response = await fetch(link, { signal });
    const json = await response.json();
    setLobbies(json);
    setLoadingLobby(false);
  } catch (error) {
    if (error.name !== 'AbortError') {
      console.error('获取大厅数据失败:', error);
      setLoadingLobby(false);
    }
  }
};

useEffect(() => {
  // 创建AbortController实例,用于管理请求取消
  const controller = new AbortController();
  const signal = controller.signal;

  // 初始加载一次数据
  fetchRooms(signal);
  fetchLobbies(signal);

  // 设置定时请求
  const intervalId = setInterval(() => {
    fetchRooms(signal);
    fetchLobbies(signal);
  }, 5000);

  // 清理函数:组件卸载时取消所有请求+清除定时器
  return () => {
    controller.abort();
    clearInterval(intervalId);
  };
}, []);

核心逻辑说明

  1. 通过AbortController生成信号,传递给每个fetch请求
  2. 组件卸载或清理时,调用controller.abort()直接中断所有未完成的请求
  3. 捕获并忽略AbortError,避免控制台出现不必要的错误提示
  4. 定时器清理与请求取消统一在useEffect的清理函数中处理,逻辑集中清晰

备选方案:修复isMounted标记逻辑

如果仅需要阻止状态更新(不中断网络请求),可以将isMounted变量移到useEffect内部,确保所有请求共享同一挂载状态:

import { useState, useEffect } from 'react';

// 组件内部逻辑
const [isLoadingRoom, setLoadingRoom] = useState(true);
const [isLoadingLobby, setLoadingLobby] = useState(true);
const [rooms, setRooms] = useState([]);
const [lobbies, setLobbies] = useState([]);

useEffect(() => {
  let isMounted = true;

  const getRooms = async () => {
    try {
      const response = await fetch(link);
      const json = await response.json();
      if (isMounted) {
        setRooms(json);
        setLoadingRoom(false);
      }
    } catch (error) {
      console.error('获取房间数据失败:', error);
      if (isMounted) setLoadingRoom(false);
    }
  };

  const getLobbies = async () => {
    try {
      const response = await fetch(link);
      const json = await response.json();
      if (isMounted) {
        setLobbies(json);
        setLoadingLobby(false);
      }
    } catch (error) {
      console.error('获取大厅数据失败:', error);
      if (isMounted) setLoadingLobby(false);
    }
  };

  // 初始加载
  getRooms();
  getLobbies();

  const intervalId = setInterval(() => {
    getRooms();
    getLobbies();
  }, 5000);

  // 组件卸载时标记为已卸载
  return () => {
    isMounted = false;
    clearInterval(intervalId);
  };
}, []);

说明

该方案仅阻止请求完成后的状态更新,但不会中断网络请求,资源利用率不如AbortController方案,仅适合理解原理场景。


内容的提问来源于stack exchange,提问作者Erik Nilsen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 17:24:17