问题
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?
回答1:
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;
}
回答2:
@Justin because onAuthStateChanged
returns function so you can use it to clear the listener...
this.fireBaseListener = firebase.auth().onAuthStateChanged
docs: https://firebase.google.com/docs/reference/js/firebase.auth.Auth#onAuthStateChanged
Returns non-null firebase.Promise containing non-null Array of string
回答3:
Instead of checking onAuthStateChanged()
function inside componentDidMount()
you can check subscription's like this.
componentWillMount() {
//following line will help you to setState() but not required
let set = this
//this is our trick
this.unsubscribe = firebase.auth().onAuthStateChanged(user => {
if (!user) {
//navigate to guest stack
//actually im using react-navigation
set.props.navigation.navigate('Guest');
} else {
//set current user to state
set.setState({
user: user,
loading: false
})
}
});
}
//What you have to do next is unsubscribe ;)
componentWillUnmount() {
this.unsubscribe();
}
来源:https://stackoverflow.com/questions/38038343/how-to-remove-the-new-firebase-onauthstatechanged-listener-in-react