Struggling with firebase authentication flows while building an app using firebase and next.js. Everything was going smoothly until I encountered a bug or error. When my computer remains logged in to the app for some time and I refresh the page, it redirects me back to the login page. The issue seems to be related to onAuthStateChange not being checked in time for const { user } = useAuth()
to run after a refresh, leading to redirection as there is no user at initial page load. However, clicking on a protected page like the dashboard keeps me authenticated without any redirections. Below is the code for my Auth component:
AuthComp.js:
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import { useAuth } from "../../context/AuthContext";
function LoadingScreen() {
return <div className="fixed top-0 right-0 h-screen w-screen z-50 flex justify-center items-center">
<div className="animate-spin rounded-full h-32 w-32 border-t-2 border-b-2 border-gray-900"></div>
</div>
}
export function AuthComp(props) {
const [isAuthenticated, setIsAuthenticated] = useState(false)
const router = useRouter();
const { user } = useAuth();
useEffect(() => {
let out;
if (user) {
setIsAuthenticated(true)
return () => out ? out() : null
} else {
router.push('/auth')
}
return () => out;
}, [user])
if (!user && (!isAuthenticated)) {
return <LoadingScreen />;
}
return <props.Component user={user} />
};
Here is my code for my auth context file: AuthContext.js:
import React, { useState, useEffect, createContext, useContext } from 'react'
import { fbase } from '../utils/auth/firebaseClient'
export const AuthContext = createContext()
export default function AuthProvider({ children }) {
const [user, setUser] = useState(null)
const [loadingUser, setLoadingUser] = useState(true) // Helpful, to update the UI accordingly.
useEffect(() => {
// Listen authenticated user
const unsubscriber = fbase.auth.onAuthStateChanged(async (user) => {
try {
if (user) {
setUser(user);
} else {
setUser(null)
return;
}
} catch (error) {
// Most probably a connection error. Handle appropriately.
console.log('an error occurred', error);
} finally {
setLoadingUser(false)
}
})
// Unsubscribe auth listener on unmount
return () => unsubscriber()
}, [])
return (
<AuthContext.Provider value={{ user, setUser, loadingUser }}>
{children}
</AuthContext.Provider>
)
}
// Custom hook that shorthands the context!
export const useAuth = () => useContext(AuthContext)