1

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?

johnborges
  • 2,422
  • 20
  • 33
S. M. Asif
  • 3,437
  • 10
  • 34
  • 58
  • https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html This link might help, basically you will need to track if your component has unmounted, and if it has don't call setState.. – Keith Apr 01 '19 at 19:50
  • I think you are using the `async` in the wrong way, you must see if the component is mounted. Take a look at those likes about [Async didMount](https://stackoverflow.com/questions/47970276/is-using-async-componentdidmount-good) and [Prevent the warning about unmounted component](https://www.robinwieruch.de/react-warning-cant-call-setstate-on-an-unmounted-component/) – Esdras Xavier Apr 01 '19 at 19:51
  • As a further guide, think about what setState would mean for an unmounted component: the component is not part of the UI the user sees, so its state is effectively void. If you want to load data etc. in the background, do that in normal code, and make your component tap into that when it (re)mounts. Component state is for data that is relevant to presenting the component to the user. Any other data isn't really state: you should be able to get it, sure, but you shouldn't tack it into the component state for convenience. – Mike 'Pomax' Kamermans Apr 01 '19 at 20:00
  • Also the future of React is using Hooks, lifecycle methods like this are so much cleaner. For example if you had multiple lifecycle function going on in the component, keeping track of them starts to get messy,. With Hooks you can just stack multiple `useEffect` hooks and each one looks after it's own lifecycle state.. Nice :) – Keith Apr 01 '19 at 20:03
  • I am not getting these properly, can anyone help me to fix this with the given code? – S. M. Asif Apr 01 '19 at 20:16
  • @S.M.Asif Can you explain the difference between the two navigation stacks? They hold the same set screens. Is there a screen you don't want to see in a particular case? – johnborges Apr 01 '19 at 20:25
  • In my code I am using StackNavigator to order the Screens, the way I initialize them. So, that was the difference. AppStackNavigator will navigate to HomeDrawer screen and AppStackNavigator2 will navigate to WelcomeScreen @johnborges – S. M. Asif Apr 02 '19 at 15:17

2 Answers2

1

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.

S. M. Asif
  • 3,437
  • 10
  • 34
  • 58
0

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>
    );
  }
}
johnborges
  • 2,422
  • 20
  • 33