【问题标题】:React - Can't perform a React state update on an unmounted componentReact - 无法对未安装的组件执行 React 状态更新
【发布时间】:2021-07-01 00:52:23
【问题描述】:

问候我现在正在尝试调试一些代码,不知道如何修复我在标题中用于检测屏幕尺寸视图的这个 useEffect。这是我为 useEffect 得到的错误:

无法对未安装的组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏。

我的代码:

const [state, setState] = useState({
    mobileView: false,
    drawerOpen: false,
});

const { mobileView, drawerOpen } = state;

useEffect(() =>
{
    const setResponsiveness = () =>
    {
        return window.innerWidth < 1000
            ? setState((prevState) => ({ ...prevState, mobileView: true }))
            : setState((prevState) => ({ ...prevState, mobileView: false }));
    };

    setResponsiveness();

    window.addEventListener("resize", () => setResponsiveness());
}, []);

依赖数组已经是空的,我不知道还要放什么?

【问题讨论】:

  • 当您尝试更新状态但组件已经卸载时会发生这种情况,因为状态更新是异步的。

标签: javascript reactjs


【解决方案1】:

导致问题的不是 useEffect,而是在窗口大小发生变化时执行的窗口调整大小事件。

当您的函数挂载时,您正在将resize 事件添加到窗口。但是当您卸载组件时,resize 事件仍在侦听,每当窗口大小发生变化时,您的 setResponsiveness 函数就会被调用。而setResponsiveness 将尝试更新未安装组件的状态值。所以基本上你的功能组件正在泄漏内存,因为即使它已卸载 setResponsiveness 仍然作为对windo resize 事件的回调附加到。

您应该始终在componentWillUnmountuseEffect 返回函数中删除组件特定的事件侦听器,具体取决于组件类型。

const [state, setState] = useState({
    mobileView: false,
    drawerOpen: false,
});

const { mobileView, drawerOpen } = state;

function setResponsiveness() {
    return window.innerWidth < 1000
        ? setState((prevState) => ({ ...prevState, mobileView: true }))
        : setState((prevState) => ({ ...prevState, mobileView: false }));
}

useEffect(() => {
    setResponsiveness();
    window.addEventListener("resize", setResponsiveness);
    // return a cleanup function which will remove the event listener
    return () => {
        window.removeEventListener("resize", setResponsiveness);
    };
}, []);



【讨论】:

    【解决方案2】:

    通过从useEffect 返回一个回调来移除监听器,该回调将在组件卸载时运行。

    useEffect(() => {
        const setResponsiveness = () => {
            return window.innerWidth < 1000
                ? setState((prevState) => ({ ...prevState, mobileView: true }))
                : setState((prevState) => ({ ...prevState, mobileView: false }));
        };
    
        setResponsiveness();
    
        window.addEventListener("resize", setResponsiveness);
        return () => window.removeEventListener("resize", setResponsiveness);
    }, []);
    

    【讨论】:

      猜你喜欢
      • 2020-11-21
      • 2021-11-30
      • 2020-09-03
      • 2019-11-09
      • 2019-05-30
      • 2021-05-30
      相关资源
      最近更新 更多