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

React出现Can't perform state update on unmounted component警告如何解决?

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

警告含义

该警告表示你尝试在已经卸载的React组件上执行状态更新操作,该操作本身不会生效,但说明应用中存在未跟随组件生命周期销毁的异步任务、事件订阅等资源,属于内存泄漏问题。

修复方案

核心逻辑是在useEffect返回的清理函数中,销毁当前组件注册的所有异步任务、事件订阅、定时器等资源,不同场景的实现方式如下:

场景1:异步接口请求

优先使用AbortController取消未完成的请求,避免请求返回后执行状态更新:

import { useState, useEffect } from 'react'
import axios from 'axios'

function UserInfo() {
  const [user, setUser] = useState(null)

  useEffect(() => {
    // 声明请求取消控制器
    const controller = new AbortController()

    const fetchUser = async () => {
      try {
        const res = await axios.get('/api/user/info', {
          signal: controller.signal // 绑定取消信号到请求
        })
        setUser(res.data)
      } catch (err) {
        // 忽略请求主动取消产生的报错
        if (err.name !== 'AbortError') {
          console.error('请求失败', err)
        }
      }
    }

    fetchUser()

    // 清理函数:组件卸载时取消未完成的请求
    return () => controller.abort()
  }, [])

  return <div>{user?.name}</div>
}

场景2:定时器/延时器

组件卸载时清除未执行的定时器:

import { useState, useEffect } from 'react'

function CountDown() {
  const [count, setCount] = useState(60)

  useEffect(() => {
    const timer = setInterval(() => {
      setCount(prev => prev - 1)
    }, 1000)

    // 清理函数:组件卸载时清除定时器
    return () => clearInterval(timer)
  }, [])

  return <div>剩余倒计时:{count}秒</div>
}

setTimeout场景同理,使用clearTimeout在清理函数中清除即可。

场景3:事件订阅/全局监听

组件卸载时移除对应的事件监听、订阅:

import { useState, useEffect } from 'react'

function WindowWidth() {
  const [width, setWidth] = useState(window.innerWidth)

  useEffect(() => {
    const handleResize = () => {
      setWidth(window.innerWidth)
    }
    window.addEventListener('resize', handleResize)

    // 清理函数:组件卸载时移除事件监听
    return () => window.removeEventListener('resize', handleResize)
  }, [])

  return <div>窗口宽度:{width}px</div>
}

RxJS订阅、WebSocket监听等场景同理,在清理函数中执行订阅销毁、连接关闭逻辑即可。

兜底方案:挂载状态标记(不推荐优先使用)

如果遇到无法取消的异步任务(如老旧请求库不支持取消能力),可以通过挂载标记位判断是否需要更新状态:

import { useState, useEffect } from 'react'
import axios from 'axios'

function UserInfo() {
  const [user, setUser] = useState(null)

  useEffect(() => {
    let isMounted = true

    const fetchUser = async () => {
      const res = await axios.get('/api/user/info')
      // 仅组件处于挂载状态时更新状态
      if (isMounted) {
        setUser(res.data)
      }
    }

    fetchUser()

    // 清理函数:组件卸载时修改标记位
    return () => {
      isMounted = false
    }
  }, [])

  return <div>{user?.name}</div>
}

注意:该方案仅能消除警告,并没有真正取消异步任务的执行,无法解决内存泄漏的根本问题,仅作为无法取消任务场景的兜底使用


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 18:15:07