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

Can't perform a React state update报错如何通过useEffect修复?

报错含义解释

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.
这个警告的核心原因是:你的组件已经被用户关闭/路由跳转卸载了,但之前在useEffect中发起的getAllEnterprises接口请求还在运行,请求完成后的then/catch/finally回调依然执行了setEmpresas、setLoading等状态更新操作。React不允许对已卸载的组件更新状态,该操作虽然不会直接导致程序崩溃,但会造成内存泄漏——因为回调持有组件的引用,导致组件占用的内存无法被垃圾回收机制正常释放。

正确修复方案

推荐优先使用标准的AbortController方案,该方案可以主动终止未完成的请求,不仅能解决警告,还能节省不必要的带宽开销:

export function SelecionarEmpresa({ closeModalSelectCompany }: Props) {

  const { token } = useAuth();
  const { navigate } = useNavigation();

  const [loading, setLoading] = useState(true);
  const [empresas, setEmpresas] = useState([]);

  useEffect(() => {
    // 创建终止控制器实例
    const controller = new AbortController();
    const signal = controller.signal;

    getAllEnterprises(token!, '7795297', signal) // 给请求传入signal参数
      .then((res: any) => {
        // 请求成功且未被终止时再更新状态
        if (!signal.aborted) {
          setEmpresas(res);
        }
      })
      .catch((error: any) => {
        // 忽略请求主动终止的报错
        if (error.name !== 'AbortError') {
          alert("Erro ao buscar empresas" + error);
        }
      })
      .finally(() => {
        if (!signal.aborted) {
          setLoading(false);
        }
      });

    // 组件卸载时的清理函数,主动终止请求
    return () => controller.abort();
  }, []);


  // 其余渲染代码保持不变即可
  return (
    <S.Container>
      <S.Gradient colors={['#8F012A', '#E67521']}>
        <S.Image source={require('../../images/fundobnb.png')} />
        <S.SafeArea>

          {
            loading && (
              <S.ContainerLoading>
                <ActivityIndicator size="small" color="#FFF" />
                <S.Description>Carregando empresas...</S.Description>
              </S.ContainerLoading>
            )
          }

          {!loading && !empresas?.length && (
            <S.Content>
              <S.SubContent>
                <CustomIcon name="ops" size={normalize(40)} color="#FFA439" />
                <S.TitleError>Ops!</S.TitleError>
              </S.SubContent>
              <S.TextError>Você não está associado{'\n'} a nenhuma empresa.</S.TextError>
              <ButtonCompany title="Continuar sem identificação" onPress={() => navigate('Home')} />
            </S.Content>
          )}

          {!loading && empresas && empresas?.length > 0 && (
            <S.Content>
              <S.Title>Escolha</S.Title>
              <S.Description>Deseja se conectar com qual empresa?</S.Description>
              {
                empresas.length > 0 && empresas?.map((item, index) => (
                  <ButtonCompany key={index} title={item.razaoSocial} onPress={() => alert('ok')} />
                ))
              }
            </S.Content>
          )}

          <S.Button onPress={null}>
            <S.TextButton>Central de Atendimento</S.TextButton>
          </S.Button>

        </S.SafeArea>
      </S.Gradient>

    </S.Container>
  )
}

注意:如果你的getAllEnterprises是封装的fetch/axios请求,需要调整封装逻辑支持传入signal参数,fetch原生支持该参数,axios可以将signal放在请求配置项中传入。

如果暂时无法修改请求封装,可以使用临时的挂载标记方案作为过渡:

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

  getAllEnterprises(token!, '7795297')
    .then((res: any) => {
      if (isMounted) {
        setEmpresas(res);
      }
    })
    .catch((error: any) => {
      alert("Erro ao buscar empresas" + error);
    })
    .finally(() => {
      if (isMounted) {
        setLoading(false);
      }
    });

  return () => {
    isMounted = false;
  }
}, []);

该方案只是阻止了卸载后的状态更新,并没有真正终止请求,优先级低于AbortController方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 13:09:03