Reputation: 115
I am creating a basic sign in / Sign out app utilizing Firebase. When I boot the app and sign up a user, everything seems fine. But when I log out and attempt to sign up a second user I get the yellow warning below. I have read about how to avoid this warning by using isMounted()
however I have not gotten it to work and Ive read that isMounted()
is deprecated anyway. Please help. Thank you!
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in %s.%s, the componentWillUnmount method,
in HomeScreen (at SceneView.js:9)
in SceneView (at StackViewLayout.tsx:900)
in RCTView (at createAnimatedComponent.js:151)
in AnimatedComponent (at StackViewCard.tsx:106)
in RCTView (at createAnimatedComponent.js:151)
in AnimatedComponent (at screens.native.js:71)
in Screen (at StackViewCard.tsx:93)
in Card (at createPointerEventsContainer.tsx:95)
in Container (at StackViewLayout.tsx:975)
From the warning, I believe my problem is in my HomeScreen.js
below:
import React from 'react';
import { Text, Button, View, StyleSheet, Image } from 'react-native'
import * as firebase from 'firebase';
export default class HomeScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
email: ""
}
}
static navigationOptions = {
title: "Home",
header: null
}
componentDidMount() {
firebase.auth().onAuthStateChanged(authenticate => {
if (authenticate) {
this.setState({
email: authenticate.email,
name: authenticate.displayName
});
} else {
this.props.navigation.replace("SignIn");
}
});
}
signOutUser = () => {
firebase
.auth()
.signOut()
.then(() => console.log("signout"))
.catch(error => alert(error.message))
}
render() {
return (
<View style={styles.container}>
<View style={styles.logoContainer}>
<Image source={require('../assets/logo.png')} />
<Text>Home Screen</Text>
</View>
<View>
<Text>Hey {this.state.name}</Text>
<Text>Logged in as {this.state.email}</Text>
</View>
<Button
style={styles.button}
title="Log Out"
full
rounded
success
onPress={() => {
this.signOutUser();
}}
>
<Text style={styles.buttonText}>Sign Out</Text>
</Button>
</View >
);
}
}
Thanks again! -Matt
Upvotes: 0
Views: 593
Reputation: 501
You need to unsubscribe the firebase listener, or else it will lead to this memory leakage issue.
import React from 'react';
import { Text, Button, View, StyleSheet, Image } from 'react-native'
import * as firebase from 'firebase';
export default class HomeScreen extends React.Component {
unsubscribeUserAuthStateChangedListener = null;
constructor(props) {
super(props);
this.state = {
name: "",
email: ""
}
}
static navigationOptions = {
title: "Home",
header: null
}
componentDidMount() {
this.unsubscribeUserAuthStateChangedListener = firebase.auth().onAuthStateChanged(authenticate => {
if (authenticate) {
this.setState({
email: authenticate.email,
name: authenticate.displayName
});
} else {
this.props.navigation.replace("SignIn");
}
});
}
componentWillUnmount() {
if (this.unsubscribeUserAuthStateChangedListener) {
this.unsubscribeUserAuthStateChangedListener();
}
}
signOutUser = () => {
firebase
.auth()
.signOut()
.then(() => console.log("signout"))
.catch(error => alert(error.message))
}
render() {
return (
<View style={styles.container}>
<View style={styles.logoContainer}>
<Image source={require('../assets/logo.png')} />
<Text>Home Screen</Text>
</View>
<View>
<Text>Hey {this.state.name}</Text>
<Text>Logged in as {this.state.email}</Text>
</View>
<Button
style={styles.button}
title="Log Out"
full
rounded
success
onPress={() => {
this.signOutUser();
}}
>
<Text style={styles.buttonText}>Sign Out</Text>
</Button>
</View >
);
}
}
Upvotes: 1
Reputation: 130
Self explanatory, Like the name unmounted, This happens when setState is called after the screen has been existed.
onAuthStateChanged is a listener and can be called at anytime, I'd advise you control this yourself and check if screen is mounted before setting state.
constructor(props) {
super(props);
this.state = {
name: "",
email: "",
isMounted: true
}
}
componentDidMount() {
firebase.auth().onAuthStateChanged(authenticate => {
if (authenticate) {
if(this.state.isMounted) {
this.setState({
email: authenticate.email,
name: authenticate.displayName
});
}
} else {
this.props.navigation.replace("SignIn");
}
});
}
componentwillUnMount() {
this.setState({isMounted: false})
}
Upvotes: 0