1

I am trying to navigate a user on login, however it seems like onAuthStateChanged does not work correctly as after logging in, the currentUser is still null and as such is navigated to the home page even though they are supposed to be navigated to a verification page (protected navigation). Below is the relevant code in the AuthContext file.

export default function AuthContextProvider({ children }) {
    const [currentUser, setCurrentUser] = useState(null)
    const [loading, setLoading] = useState(true)

    useEffect(() => {
        const unsubscribe = onAuthStateChanged(auth, (user) => {
            setCurrentUser(user)
            setLoading(false)
        })
        return () => {
            unsubscribe()
    
        }
    }, [])
}

The relevant login function is here

try {     
            setLoading(true)
            await login(email, pw).then(response => {
                console.log(currentUser)
                navigate('/verification')
            })
        } catch(error) {
            if(error.code === "auth/user-not-found") {
                console.log(error.message)
                setError("Account does not exist. Please try again with a different email or create a new account.")
            }
            if(error.code === "auth/wrong-password") {
                console.log(error.message)
                setError("Wrong password. Please try again with a different password.")
            }
            
        }     
        setLoading(false)

And finally the protected route is here

const router = createBrowserRouter(
    createRoutesFromElements(
        <Route path='/' element={<Layout />}>
            <Route exact index element={<HomePage />} />
            <Route exact path='/signup' element={<SignUp />} />
            <Route exact path='/login' element={<Login />} />
            <Route element={<ProtectedRoute />}>
              <Route exact path='/verification' element={<Verification />} />
            </Route>
            <Route path='*' element={<Error404 />} />
        </Route>
    )
);

function ProtectedRoute({children}) {
  const {currentUser} = useAuth()

  if(currentUser === null) {
    return <HomePage />
  }
  return currentUser ? <Outlet/> : <Navigate to="/" /> 
}

This issue only occurs on the first log in where the navigation goes to the home page. However when I manually type "/verification" on the address bar I am routed correctly to the verification page and on console log shows as logged in. So I feel it is logging in, but there is some form of delay (but I have an await call so unsure why the page does not wait for the user to be set before rendering the page)

I am on firebase v10.1 and react-router 6.4

Edit: After changing to a new protected route code (edited in the code block), the redirection works, however, when I am logged out and I try to access the /verification route, my code does not redirect to homepage. I need it to be able to redirect to the homepage when the user is not logged in and tries to access the verification. I have added a codesandbox https://codesandbox.io/p/sandbox/flamboyant-haibt-hwrhzj

This shows the issue I have on hand. The relevant routes if needed are:

/login
/signup
/verification
Ramana
  • 23
  • 3
  • 1
    The initial `currentUser` state is null and `ProtectedRoute` isn't waiting for the current authentication status to be verified when the app mounts, so the redirection occurs. Use a different initial value that doesn't match either of the ***confirmed*** authenticated/unauthenticated "states". `ProtectedRoute` is also breaking the Rules of Hooks by conditionally calling the `useEffect` hook. Use and return/render the `Navigate` component instead. Also, just FYI, it's generally considered anti-pattern to mix `async/await` with Promise chains. – Drew Reese Aug 21 '23 at 15:49
  • Hi @Drew, thanks for your suggestion, I have implemented the change according to your comment and redirection works on log in, however, when a user who is not logged in tries to access the protected page, he is not redirected to the home page - I believe it is because I am returning null. If I return HomePage component, the link still shows "/verification", if I return a Navigate component, the routing breaks for a signed in user. I have edited the protected route code to show my latest code. – Ramana Aug 22 '23 at 01:01
  • The `onAuthStateChanged` callback returns `null` when a user is not authenticated, so you don't want the initial `currentUser` state to also be `null`, use `undefined` instead, e.g. `const [currentUser, setCurrentUser] = useState()`. The `ProtectedRoute` component should then explicitly check for `undefined` when returning the "loading" state, e.g. `if (currentUser === undefined) { return null; // or loading spinner/etc }`. I think this should get your code straightened out and working. – Drew Reese Aug 22 '23 at 01:50
  • I tried with your code changes, however it still does not work. – Ramana Aug 22 '23 at 02:57
  • Perhaps there's an additional issue somewhere. Think you could create a ***running*** [codesandbox](https://codesandbox.io/) demo that reproduces the issue you have still that we could inspect live? You can mock the `onAuthStateChanged` function and callbacks so you don't need to connect to your firebase backend. – Drew Reese Aug 22 '23 at 03:03
  • @DrewReese I have added it to sandbox with a temporary firebase API. https://codesandbox.io/p/sandbox/flamboyant-haibt-hwrhzj As you can see, after logging in it goes directly to the homepage instead of /verification although it works as expected in being protected (only logged in user can enter /verification) - you can try by manually entering in the address bar If you need the following routes: /login /signup /verification – Ramana Aug 22 '23 at 05:03
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/254995/discussion-between-drew-reese-and-ramana). – Drew Reese Aug 22 '23 at 05:24

0 Answers0