无法对未安装的组件执行 React 状态更新(useEffect 反应挂钩)

Posted

技术标签:

【中文标题】无法对未安装的组件执行 React 状态更新(useEffect 反应挂钩)【英文标题】:Can't perform a React state update on an unmounted component (useEffect react hooks) 【发布时间】:2020-08-02 23:51:24 【问题描述】:

我正在使用以下代码(useEffect)来更改滚动类。

import  useState, useEffect  from "react"

export const useScrollHandler = () => 
  // setting initial value to true
  const [scroll, setScroll] = useState(1)

  // running on mount
  useEffect(() => 
    const onScroll = () => 
      const scrollCheck = window.scrollY < 10
      if (scrollCheck !== scroll) 
        setScroll(scrollCheck)
      
    

    // setting the event handler from web API

    document.addEventListener("scroll", onScroll)

    // cleaning up from the web API
    return () => 
      document.removeEventListener("scroll", onScroll)
    
  , [scroll, setScroll])
  return scroll

即使我使用了清理功能,当我执行 history.push("/") 时也会出现以下错误

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

如何解决?

这里我使用了useScrollHandler。

function HomeNav() 
  const scroll = useScrollHandler()
  return (
    <React.Fragment>
      <nav
        className=
          scroll ? "navbar navbar-expand-lg navbar-light fixed-top py-3" : "navbar navbar-expand-lg navbar-light fixed-top py-3 navbar-scrolled"
        
        id="mainNav"
      >
      </nav>
    </React.Fragment>
  )


export default HomeNav

【问题讨论】:

为什么在 useEffect 的第二个 args 数组中将 setScroll 作为依赖项?另外,你可以在你使用useScrollHandler的地方添加代码吗? 您要删除unmount 上的eventListener 吗? @SarthakAggarwal 是的。 【参考方案1】:

试试这个来删除unmount上的EventListener

const onScroll = () => 
      const scrollCheck = window.scrollY < 10
      if (scrollCheck !== scroll) 
        setScroll(scrollCheck)
      


useEffect(() => 

    // Add event listener on component mount
    document.addEventListener("scroll", onScroll)

    // removing event listener on component unmount
    return () => 
      document.removeEventListener("scroll", onScroll)
    
, []) // This useEffect will act as componentDidMount and return function as componentWillUnmount as no dependencies are given.


【讨论】:

【参考方案2】:

我认为您在事件处理程序中不需要scroll,并且保证setScroll 保持不变,这意味着您的效果处理程序可以使用[] 作为其依赖数组。 简化这可能会有所帮助。

import  useState, useEffect  from "react"

export const useScrollHandler = () => 
  // setting initial value to true
  const [scroll, setScroll] = useState(true);
  // running on mount
  useEffect(() => 
    const onScroll = () => setScroll(window.scrollY < 10)
    // setting the event handler from web API
    document.addEventListener("scroll", onScroll)
    // cleaning up from the web API
    return () => 
      document.removeEventListener("scroll", onScroll)
    
  , [])
  return scroll

【讨论】:

以上是关于无法对未安装的组件执行 React 状态更新(useEffect 反应挂钩)的主要内容,如果未能解决你的问题,请参考以下文章

错误:无法对未安装的组件执行 React 状态更新

无法对未安装的组件执行 React 状态更新。内存泄漏

无法使用 fetch POST 方法对未安装的组件执行 React 状态更新

警告:无法对未安装的组件执行 React 状态更新

警告:无法对未安装的组件执行 React 状态更新。在功能组件中

无法对未安装的组件执行 React 状态更新(useEffect 反应挂钩)