I have a simple react app that uses firebase for auth. The problem with using firebase is that I need to wait for the onAuthStateChanged callback to fire before I know for certain whether or not a user is logged in or not, which only takes a second or so.
I'd like to display a loading message for that time period, so that when the app is displayed to the user I can be certain that we have determined whether or not a user. Once the callback has been triggered and we have a determinate state for the user, load the app.
The problem with the code below is that it looks like the value of loading is being changed from false to true faster than the onAuthStateChanged callback is being triggered, which means that the app is being loaded faster than we have a determinate state for the user. So if someone navigates to the dashboard there is a redirect to login there that triggers first despite the user actually being logged in.
I really need to be able to set a variable like displayApp that is set to true inside the callback. However if I do that I get an error message saying
Assignments to the 'displayApp' variable from inside React Hook useEffect will be lost after each render.
which does make sense since the component is re-rendered each time and the value will be lost.
What's the best way to persist a variable in this situation so that I can only display my app once the callback has triggered?
const auth = firebase.auth();
const AuthStateContext = React.createContext(undefined);
function App() {
const user = useFirebaseAuth();
const [value, loading] = useAuthState(auth);
console.log("Loading: ", loading);
let displayApp = false;
useEffect(() => {
firebase.auth().onAuthStateChanged(authUser => {
console.log("Auth user:", authUser);
console.log("Loading (auth): ", loading);
displayApp = true;
})
})
return (
<>
{!loading &&
<Switch>
<Route path="/" exact>
{user ? <Dashboard/> : <Login/> }
</Route>
<Route path="/dashboard">
<Dashboard/>
</Route>
<Route path="/login">
<Login/>
</Route>
</Switch>
}
{loading &&
<h4>Loading...</h4>
}
</>
)
}
export default function Dashboard(props){
const auth = firebase.auth();
const user = useFirebaseAuth();
console.log("Dashboard");
if(!user){
return (
// <h4>Not logged</h4>
<Redirect to="/login"/> //Since the app is loaded before the user is retrieved, this gets triggered despite the user being logged in
)
}
return (
<>
<h1>Dashboard</h1>
<h4>{auth.currentUser?.displayName}</h4>
<button onClick={() => firebase.auth().signOut()}>Sign out</button>
</>
)
}