I have a react native application that show's different navigators based on whether or not there is an authenticated firebase user.
Here's my main App class:
export default class App extends Component {
state = { loggedIn: null }
componentWillMount() {
firebase.initializeApp({...});
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.setState({ loggedIn: true });
} else {
this.setState({ loggedIn: false });
}
});
}
renderContent() {
switch (this.state.loggedIn) {
case true:
return (
<MenuContext>
<MainNavigator />
</MenuContext>
);
case false:
return (
<AuthNavigator />
);
default:
return (
<View style={styles.spinnerStyle}>
<Spinner size="large" />
</View>
);
}
}
render() {
return (
<Provider store={store}>
{this.renderContent()}
</Provider>
);
}
}
Now this works perfectly fine with re-rendering the correct Navigator when a user logs in.
The problem I have is with logging out. In my MainNavigator
(the one that shows when a user is logged in), I have a logout button which logs the user out. Implemented like this:
signOutUser = async () => {
try {
await firebase.auth().signOut();
} catch (e) {
console.log(e);
}
}
render() {
return (
...
<Button title="logout" onPress={() => this.signOutUser()} />
)
}
This does what is expected, however, I get the following warning which I want to resolve:
Warning: Can only update a mounted or mounting component. This usually means you called setState, replaceState or forceUpdate on an unmounted component. This is a no-op.
What is the best practice way of implementing this logout functionality?
Edit: I'm using the react-navigation
library for managing my application navigation.
I think generating your Navigator depending on a state of App component can be dangerous and can lead to this issue. On logout you should redirect to the component in charge of registration or login and don't let the state in charge of this with regenerating a part of an another navigation.
What you can do is in your App Component, instead of returning MainNavigator or AuthNavigator, you can return both Navigator and add a Route called Loading for example, who will render a loading screen and who will be the initialRoute in charge of routing your app depending on the user is logged or not.
Example of StackNavigator with this case
const Navigator = StackNavigator({
Main: {
screen: MainComponent,
},
Auth: {
screen: AuthComponent,
},
Loading: {
screen: LoadingComponent
},
},{
initialRouteName : 'Loading'
});
in your LoadingComponent you will render your spinner
render() {
return(
<View style={styles.spinnerStyle}>
<Spinner size="large" />
</View>
);
}
And in componentDidMount of LoadingComponent :
firebase.auth().onAuthStateChanged(user => {
if (user) {
navigate('Home');
} else {
navigate('Login');
}
});
With that the loading screen will be display when you open your app and then redirect to the good page depending of user is logged or not.
And in your signOutUser redirect to Login page
signOutUser = async () => {
try {
await firebase.auth().signOut();
navigate('Auth');
} catch (e) {
console.log(e);
}
}
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