Home > other >  Simple Auth method leads to "Maximum update depth exceeded"
Simple Auth method leads to "Maximum update depth exceeded"

Time:01-16

I wanted to create a simple authentication using react and firebase. So my code is fairly simple. I use the firebase auth to create an user (works like a charm) and also to get the user (works like a charm). Then I save the corresponding token in the sessionStorage. Now it gets tricky: I just want to call this token to check, if the user has permission to access a page. So my code looks like this:

    function InternCheckPage() {

    let navigate = useNavigate();

    useEffect(() =>{
        let authToken = sessionStorage.getItem('auth_token')

        if(authToken){
            navigate('/intern')
        }
        if(!authToken){
            navigate('/login')
        }

    })

    return (
        <div className="App">
            <div className="App-header">
                <p>
                    InternCheck
                </p>
            </div>
        </div>
    );
}
export default InternCheckPage;

However, this leads to the following error:

Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.

and my page stops to respond. Frankly I dont know what I did wrong. I just took this code snipped from a tutorial where it's supposed to work just fine.

Any advice?

CodePudding user response:

You shouldn't really use useEffect without a dependency array, I think that in this case a simple empty array as the second argument to useEffect would do the trick for you.

useEffect(() => {
  ...code
}, []) 

meaning code runs only the first time the component gets rendered.

CodePudding user response:

Here's another approach that I've used that might be helpful. Rather than manage storing and retrieving the authenticated user yourself, you could delegate that work to the onAuthStateChanged function that the firebase SDK provides.

What you see below is a custom hook that is responsible for returning the authenticated user.

import { useEffect, useRef, useState } from 'react';

import { getAuth, onAuthStateChanged, User } from '@firebase/auth';

import { app } from '../../configuration/FirebaseConfiguration';

const useAuth = () => {
  const [user, setUser] = useState<User | null>(null);
  const auth = getAuth(app);

  let mounted = useRef<boolean>(false);

  useEffect(() => {
    mounted.current = true;
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      console.log("onAuthUserChanged", user);
      if (user) {
        if (mounted.current) {
          setUser(user);
        }
      } else {
        if (mounted.current) {
          setUser(null);
        }
      }
    });

    return () => {
      mounted.current = false;
      unsubscribe();
    };
  }, [auth]);

  return {
    user,
    auth,
  };
};

export { useAuth };

You can call it as so in any other component

 const { user } = useAuth();

And, here's the github repository I created that uses this approach https://github.com/SangeetAgarwal/FirebaseAuthReactRouterv6

Here's link to resource I found very helpful when I was learning firebase authentication https://firebase.google.com/docs/web/setup.

So, now with the custom authentication hook above, your specific code would look something like this

function InternCheckPage() {

    let navigate = useNavigate();
    
    const { user } = useAuth();

    useEffect(() => {
        // let authToken = sessionStorage.getItem('auth_token')

        if (user) {
            navigate('/intern')
        } else {
            navigate('/login')
        }
        //if(!authToken){
        //    navigate('/login')
        //}

    }, [user])

    return (
        <div className="App">
            <div className="App-header">
                <p>
                    InternCheck
                </p>
            </div>
        </div>
    );
}

export default InternCheckPage;

CodePudding user response:

Try using this code:

import React, { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';

export default function Test_1() {
let navigate = useNavigate();

useEffect(() => {
let authToken = sessionStorage.getItem('auth_token');

if (authToken) {
  navigate('/intern');
} else {
  navigate('/login');
}
}, []);

return (
<div className='App'>
  <div className='App-header'>
    <p>InternCheck</p>
  </div>
</div>
);
}

I changed your code a bit due to fix the bug. This would hopefully work now.

  •  Tags:  
  • Related