It is not possible to tell whether a user will be signed when a page starts loading, there is a work around though.
You can memorize last auth state to localStorage to persist it between sessions and between tabs.
Then, when page starts loading, you can optimistically assume the user will be re-signed in automatically and postpone the dialog until you can be sure (ie after onAuthStateChanged
fires). Otherwise, if the localStorage
key is empty, you can show the dialog right away.
The firebase onAuthStateChanged
event will fire roughly 2 seconds after a page load.
// User signed out in previous session, show dialog immediately because there will be no auto-login
if (!localStorage.getItem('myPage.expectSignIn')) showDialog() // or redirect to sign-in page
firebase.auth().onAuthStateChanged(user => {
if (user) {
// User just signed in, we should not display dialog next time because of firebase auto-login
localStorage.setItem('myPage.expectSignIn', '1')
} else {
// User just signed-out or auto-login failed, we will show sign-in form immediately the next time he loads the page
localStorage.removeItem('myPage.expectSignIn')
// Here implement logic to trigger the login dialog or redirect to sign-in page, if necessary. Don't redirect if dialog is already visible.
// e.g. showDialog()
}
})
I am using this with
React and
react-router. I put the code above into
componentDidMount
of my App root component. There, in the render, I have some
PrivateRoutes
<Router>
<Switch>
<PrivateRoute
exact path={routes.DASHBOARD}
component={pages.Dashboard}
/>
...
And this is how my PrivateRoute is implemented:
export default function PrivateRoute(props) {
return firebase.auth().currentUser != null
? <Route {...props}/>
: localStorage.getItem('myPage.expectSignIn')
// if user is expected to sign in automatically, display Spinner, otherwise redirect to login page.
? <Spinner centered size={400}/>
: (
<>
Redirecting to sign in page.
{ location.replace(`/login?from=${props.path}`) }
</>
)
}
// Using router Redirect instead of location.replace
// <Redirect
// from={props.path}
// to={{pathname: routes.SIGN_IN, state: {from: props.path}}}
// />