I'm using React contexts in order to hold my authentication state for my application. Currently, I'm having an issue where whenever I try and hit /groups/:id
, it always redirects me to /login
first and then to /UserDash
. This is happening because the context of my AuthProvider isn't updating fast enough, and my Private Route utilized the AuthContext to decide whether to redirect or not.
<AuthProvider>
<Router>
<Switch>
<LoggedRoute exact path = "/" component = {Home}/>
<Route exact path = "/login" component = {Login}/>
<PrivateRoute exact path = "/groups/:id" component = {GroupDash}/>
<PrivateRoute exact path = "/UserDash" component = {UserDash}/>
</Switch>
</Router>
</AuthProvider>
In another file:
export const AuthContext = React.createContext();
export const AuthProvider = ({children}) => {
const [currentUser, setCurrentUser] = useState(null);
useEffect(() => {
firebaseApp.auth().onAuthStateChanged(setCurrentUser);
},[]);
return (
<AuthContext.Provider
value = {{currentUser}}
>
{children}
</AuthContext.Provider>
);
My private route:
const PrivateRoute = ({component: RouteComponent, ...rest}) => {
const {currentUser} = useContext((context) => AuthContext);
return (
<Route
{...rest}
render={routeProps => (currentUser) ? (<RouteComponent{...routeProps}/>) : (<Redirect to={"/login"}/>)}
/>
)
};
And my login page
const {currentUser} = useContext(AuthContext);
if (currentUser) {
return <Redirect to = "/UserDash" />
}
return (
<button onClick={(e) => {googleLogin(history)}}>Log In</button>
);
Is there any way to force the context to load before the private route redirects the user to the login page? I've tried using firebase.auth().currentUser inside my PrivateRoute instead, but that also fails and I still get redirected to "/login"
, before getting pushed to "/UserDash"
.
Since useEffect runs after a render and the value being fetched in useEffect is from a async call what can do is to actually maintain a loading state till data is available like
export const AuthContext = React.createContext();
export const AuthProvider = ({children}) => {
const [currentUser, setCurrentUser] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
firebaseApp.auth().onAuthStateChanged((user) => {
setCurrentUser(); setIsLoading(false)
});
},[]);
return (
<AuthContext.Provider
value = {{currentUser, isLoading}}
>
{children}
</AuthContext.Provider>
);
}
Then in privateRoute
const PrivateRoute = ({component: RouteComponent, ...rest}) => {
const {currentUser, isLoading} = useContext((context) => AuthContext);
if(isLoading) return <div>Loading...</div>
return (
<Route
{...rest}
render={routeProps => (currentUser) ? (<RouteComponent{...routeProps}/>) : (<Redirect to={"/login"}/>)}
/>
)
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With