Hard refreshes on my SPA React/Firebase application does not maintain auth state on immediate execution of a function. I have a workaround, but it's sketchy.
My react routes utilize the onEnter
function to determine whether or not the user is authenticated or not. For instance
<Route path="/secure" component={Dashboard} onEnter={requireAuth}/>
Furthermore, my requireAuth
function looks like this:
function (nextState, replace) {
console.log('requireAuth', firebase.auth().currentUser);
if (!firebase.auth().currentUser) {
console.log('attempting to access a secure route. please login first.');
replace({
pathname: '/login',
state: { nextPathname: nextState.location.pathname }
});
}
};
However, on a hard refresh there is a slight delay on firebase.auth().currentUser
. It's null at first, then executes a POST
to firebase servers in order to determine auth state. When it returns the currentUser
object is populated. This delay causes issues though.
My hacky solution is the following: update: this doesn't actually work...
function (nextState, replace) {
setTimeout(function () {
console.log('requireAuth', firebase.auth().currentUser);
if (!firebase.auth().currentUser) {
console.log('attempting to access a secure route. please login first.');
replace({
pathname: '/login',
state: { nextPathname: nextState.location.pathname }
});
}
}, 50);
};
Simply wrap it in a timeout. However, I really don't like this... any thoughts?
Update:
I have also tried to wrap it within a onAuthStateChanged
listener, which should be more accurate than a setTimeout
with a definitive time delay. Code as follows:
function (nextState, replace) {
var unsubscribe = firebase.auth().onAuthStateChanged(function (user) {
if (!user) {
console.log('attempting to access a secure route');
replace({
pathname: '/login',
state: { nextPathname: nextState.location.pathname }
})
console.log('should have called replace');
}
unsubscribe();
});
// setTimeout(function () {
// console.log('requireAuth', firebase.auth().currentUser);
// if (!firebase.auth().currentUser) {
// console.log('attempting to access a secure route. please login first.');
// replace({
// pathname: '/login',
// state: { nextPathname: nextState.location.pathname }
// });
// }
// }, 50);
};
The two log statements are executed, but react-router replace
does not seem to be executed correctly. Perhaps that's a different question for the react-router experts.
update 2:
It was late at night when I was working on this. Apparently setTimeout
doesn't actually work either.
Works by managing localStorage. Here is example how I do it.
constructor(props) {
super(props);
let authUser = null;
// setting auth from localstorage
for (let key in localStorage) {
if (key === storageId) {
authUser = {};
break;
}
}
this.state = {authUser};
}
componentDidMount() {
firebase
.auth
.onAuthStateChanged(authUser => {
if (authUser) {
localStorage.setItem(storageId, authUser.uid);
} else {
localStorage.removeItem(storageId);
}
// change state depending on listener
authUser
? this.setState({authUser})
: this.setState({authUser: null});
});
}
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