0

I read a lot of similar questions but it seems my questions is a little different.
I am trying to login and I get the following 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.

I am attaching the AuthContext.js that handles all the logic hoping you can explain me what is wrong and what knowledge it indicates I need to learn.

import React, { useContext, useState } from 'react'
import {postData} from '../adapters/authAdapter';

const AuthContext = React.createContext();

export function useAuth() {
    return useContext(AuthContext);
}

export function AuthProvider({children}) {
    const [currentUser,setCurrentUser] = useState(null);

    async function login(email,password) {
        const adaptedRes = await postData('log-in',{email,password});
        if(adaptedRes.err) {
        throw new Error(adaptedRes.message)
        } else {
        return setCurrentUser(adaptedRes.data);
        }
    }

    const value = {
        currentUser,
        login
    };

    return (
        <AuthContext.Provider value={value}>
            {children}
        </AuthContext.Provider>
    )
}

Thank you in advance

  • See [Can't perform a React state update on an unmounted component](https://stackoverflow.com/questions/53949393/cant-perform-a-react-state-update-on-an-unmounted-component) – Shivam Jha Apr 07 '21 at 18:40
  • can you explain which hook and where I need to implement? – Marcos Molina Apr 07 '21 at 18:51
  • The error means that your `setCurrentUser()` function is being called, when `AuthProvider` is not courrently mounted. That's why, use `useRef()` to check if your `AuthProvider` is mounted, and then set state as mentioned in the link – Shivam Jha Apr 07 '21 at 18:54
  • but I am calling the async function out of AuthProvider. Every answer is like useEffect(.... asyncFunction()...) – Marcos Molina Apr 07 '21 at 18:58
  • Issue is as others say, the `AuthProvider ` component is being unmounted ***before*** `setCurrentUser` is called. Instead of putting a band-aid fix in to keep the state update from occurring you should figure out why your auth provider isn't mounted. This is one of those provider components you typically want wrapping your *entire* `app` and mounted at all times. My guess is you've narrowed the scope of this auth provider too much to just around your auth component UI and then you navigate elsewhere and the provider is no longer available. – Drew Reese Apr 07 '21 at 19:17
  • I navigate to other component where I use UseAuth(). Is it the same as you described? – Marcos Molina Apr 07 '21 at 19:33

1 Answers1

1

The error means that your setCurrentUser() function is being called, when AuthProvider is not currently mounted. That's why, use useRef() to check if your AuthProvider is mounted, and then set state as mentioned in the link:

export function AuthProvider({children}) {
    const [currentUser,setCurrentUser] = useState(null);
    const isMounted = useRef(false);

    useEffect(() => {
        // Becomes true on component mount
        isMounted.current = true;
         
        // becomes false on unmount
        return () => {isMounted.current = false;}
    
    
    }, [])

    async function login(email,password) {
        const adaptedRes = await postData('log-in',{email,password});
        if(adaptedRes.err) {
        throw new Error(adaptedRes.message)
        } else {
            if(!isMounted.current) {
            // Check if component is mounted
            console.log('component is not mounted');
            return;
        }
        return setCurrentUser(adaptedRes.data);
        }
    }

    const value = {
        currentUser,
        login
    };

    return (
        <AuthContext.Provider value={value}>
            {children}
        </AuthContext.Provider>
    )
}

Update As Drew Pointed out:

Issue is as others say, the AuthProvider component is being unmounted before setCurrentUser is called. Instead of putting a band-aid fix in to keep the state update from occurring you should figure out why your auth provider isn't mounted. This is one of those provider components you typically want wrapping your entire app and mounted at all times. My guess is you've narrowed the scope of this auth provider too much to just around your auth component UI and then you navigate elsewhere and the provider is no longer available.

So, you should also check this, as if you are getting this error, then there is implementation problem somewhere.

Shivam Jha
  • 3,160
  • 3
  • 22
  • 36
  • Works! Is it the problem common using ContextAPI or I am not doing it right ? It seems like "unneeded" complexity – Marcos Molina Apr 07 '21 at 19:20
  • @MarcosMolina Problem is nothing to do with the Context API. It's just a normal React component issue. See my comment above. – Drew Reese Apr 07 '21 at 19:22
  • Thanks for pointing this out Drew. I have updated the answer, And @MarcosMolina, if you are satisfied, then please accept my answer. – Shivam Jha Apr 08 '21 at 05:27
  • As said, I moved the AuthProvider to the App but I still get the error. In index.js. ReactDOM.render( , document.getElementById('root') ); – Marcos Molina Apr 08 '21 at 06:58