S. M. Asif
S. M. Asif

Reputation: 3709

How to solve: Can't call setState(or forceUpdate) on an unmounted component warning in React-Native?

In my React-native project in the HomeScreen, I get some values from AsyncStorage. After getting this value I compare it and take decision in which screen it will go next. If the getValue is null then it will go the WelcomeScreen and if it is not null then it will go the HomeDrawer Screen.

Here I have provided the code-

import React from 'react';
import { StyleSheet, Text, View, AsyncStorage } from 'react-native';
import {StackNavigator} from 'react-navigation';
import WelcomeScreen from './WelcomeScreen';
import LoginScreen from './components/LoginScreen';
import NoteMeHome from './components/NoteMeHome';
import HomeDrawer from './HomeDrawer/HomeDrawer';
import SettingsScreen from './components/SettingsScreen';

class HomeScreen extends React.Component {

  state = {
    getValue: '',

  }

  async componentDidMount() {

    const token = await AsyncStorage.getItem('toke');
    this.setState({ getValue: token });

  }

  render() {
    console.log('#ZZZ:', this.state.getValue);

    if(this.state.getValue !== null) {
      return (
        <AppStackNavigator/>
      );
    } else {
      return (
        <AppStackNavigator2/>
      );
    }

  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});


const AppStackNavigator = new StackNavigator({
  HomeDrawer: {screen:HomeDrawer},
  WelcomeScreen: {screen:WelcomeScreen},


  LoginScreen: {screen:LoginScreen},
  NoteMeHome: {screen:NoteMeHome},

  SettingsScreen: {screen:SettingsScreen}

})

const AppStackNavigator2 = new StackNavigator({
  WelcomeScreen: {screen:WelcomeScreen},
  HomeDrawer: {screen:HomeDrawer},

  LoginScreen: {screen:LoginScreen},
  NoteMeHome: {screen:NoteMeHome},

  SettingsScreen: {screen:SettingsScreen}

})

export default HomeScreen;

Now, after running this, if I get null value in the variable getValue , then it is showing the following warning-

Warning: Can't call setState(or forceUpdate) on an unmounted component. this is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscription and asynchronous tasks in the componentWillUnmount method.

So, how can I solve this warning issue?

Upvotes: 1

Views: 328

Answers (2)

johnborges
johnborges

Reputation: 2533

A better solution would be to use the SwitchNavigator from react-navigation since your navigation stacks are identical and you only want to route to the first screen based on that token.

see example

import React from 'react';
import { StyleSheet, Text, View, AsyncStorage } from 'react-native';
import {StackNavigator, createSwitchNavigator} from 'react-navigation';
import WelcomeScreen from './WelcomeScreen';
import LoginScreen from './components/LoginScreen';
import NoteMeHome from './components/NoteMeHome';
import HomeDrawer from './HomeDrawer/HomeDrawer';
import SettingsScreen from './components/SettingsScreen';

const AppStackNavigator = new StackNavigator({
  HomeDrawer: {screen:HomeDrawer},
  LoginScreen: {screen:LoginScreen},
  NoteMeHome: {screen:NoteMeHome},
  SettingsScreen: {screen:SettingsScreen}
});

export default createAppContainer(createSwitchNavigator(
  {
    LaunchScreen,
    WelcomeScreen,
    AppStackNavigator,
  },
  {
    initialRouteName: 'LaunchScreen',
  }
));

class LaunchScreen extends React.Component {
  constructor(props) {
    super(props);
    this._getToken();
  }

  // Fetch the token from storage then navigate to the appropriate place
  _getToken = async () => {
    const tok = await AsyncStorage.getItem('toke');

    // This will switch to the Welcome screen or main AppStack. Then this launch
    // screen will be unmounted and thrown away.
    this.props.navigation.navigate(tok ? 'AppStackNavigator' : 'WelcomeScreen');
  };

  // Render any loading content that you like here
  render() {
    return (
      <View>
        {/*...*/}
      </View>
    );
  }
}

Upvotes: 0

S. M. Asif
S. M. Asif

Reputation: 3709

I don't know whether it's a good practice or not. The problem was- my component was initializing with empty string and I was checking for null in render function. Initializing getvalue with null or checking for empty string in render would solve this issue.

So, the change I made in my code is -

state = {
    getValue: ''

  }

And it removes the warning.

Upvotes: 1

Related Questions