I'm implementing firebase auth in a react web app with react-router.
A user signs in (at /signin) with either Facebook or Google using the popup sign in, then if successful I route to the main app (/). In the main app component I listen for an auth state change:
componentWillMount() {
this.authListener = this.authListener.bind(this);
this.authListener();
}
authListener listens for the auth change:
authListener() {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log('user changed..', user);
this.setState({
User: {
displayName: user.displayName
}
});
} else {
// No user is signed in.
browserHistory.push('/signin');
}
});
}
Everything works fine, except when I sign out (and go back to /signin) and sign in again using facebook or google. Then I get an error saying:
Warning: setState(...): Can only update a mounted or mounting component.
I suspect that the onAuthStateChanged listener from the now unmounted previous logged in state app is still running.
Is there a way to remove the onAuthStateChanged listener when the App component unmounts?
According to the documentation, the onAuthStateChanged() function returns. The unsubscribe function for the observer. So you can just: var unsubscribe = firebase. auth(). onAuthStateChanged(function (user) { // handle it });
The module provides a method called onAuthStateChanged which allows you to subscribe to the users current authentication state, and receive an event whenever that state changes.
I know I am late to the game, but here's a hooks based solution:
React.useEffect(() => {
const unsubscribe = firebase.auth().onAuthStateChanged((user) => { // detaching the listener
if (user) {
// ...your code to handle authenticated users.
} else {
// No user is signed in...code to handle unauthenticated users.
}
});
return () => unsubscribe(); // unsubscribing from the listener when the component is unmounting.
}, []);
Any listeners that you have set up will also need to be torn down.
Your suspicions are very much on-spot.
You should use the componentWillUnmount lifecycle method to remove any leftover listeners that might pollute your app.
To clear up the listener, here's the relevant code:
Inside your authListener
function you need to save a reference to the listener inside your component (it is returned to you as a result of calling firebase.auth().onAuthStateChanged
). It will be a hook that will un-reference the listener and remove it.
So instead of just calling it, save the returned value as such
this.fireBaseListener = firebase.auth().onAuthStateChanged ...
And when your component un-mounts, use this code:
componentWillUnmount() {
this.fireBaseListener && this.fireBaseListener();
this.authListener = undefined;
}
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