yung peso
yung peso

Reputation: 1766

React - Can't perform a React state update on an unmounted component

Greetings I'm trying to debug some code right now, not sure how to fix this useEffect that I have in my header to detect for screen size view. Here is the error I'm getting for the 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.

My code:

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());
}, []);

The dependency array is already empty, im not sure what else to put in there though?

Upvotes: 2

Views: 1281

Answers (2)

Gulam Hussain
Gulam Hussain

Reputation: 1763

It's not useEffect that is causing the problem, it's window resize event which is being excuted whenever window size changes.

You are adding resize event to window when your function mounts. but when you unmount the component, resize event is still listening and whenever window size changes your setResponsiveness function will be called. and setResponsiveness will try to update the state values of unmounted component. So basically your functional component is leaking memory because even though it has unmounted setResponsiveness is still attached to as a callback to windo resize event.

You should always remove component specific event listener either in componentWillUnmount or in useEffect return function, depending on component type.

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);
    };
}, []);



Upvotes: 3

CertainPerformance
CertainPerformance

Reputation: 370669

Remove the listener by returning a callback from useEffect, which'll run when the component unmounts.

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);
}, []);

Upvotes: 1

Related Questions