Search code examples
javascriptreact-nativereact-navigationasyncstorage

Problems fetching initialRouteName from Async Storage


I'm new to React so I hope you'll bear with me.

I want to show the user the onboarding screen the first time they open the app. The second time, I want to show the login screen.

My approach is to change the initialRouteName in the OnboardingStack.Navigator. On first launch it should be 'Onboarding' on second launch 'Login'. I'm using asycnStorage to store these values.

Once the app opens 'Login' is added to the LaunchStatusKey. On second opening it should register that LaunchStatusKey is in fact 'Login', which should go on and set the initialRouteName to 'Login' as well. But this doesn't work.

I suspect there's a time lag between await and the launch of my app, and before it can go fetch the LaunchStatusKey and set initialRouteName to 'Login', it launches and uses the default 'Onboarding'

Any ideas on how to get around thus?

Thans for reading!

const OnboardingStack = createStackNavigator();

const App = ({ navigation }) => {

  const [initialRouteName, setInitialRouteName] = useState('')

  const save = async () => {
    try {
      await AsyncStorage.setItem("launchStatusKey", initialRouteName)
    } catch (err) {
      alert(err);
    }
  };
  save();

  const load = async () => {
    try {
      let key = await AsyncStorage.getItem("launchStatusKey")
      if (key === null) {
        console.log('It is empty')
        setInitialRouteName('Login')
      } else {
        console.log('It is not empty')

      }
    } catch (err) {
      alert(err);
    }
  }; 

  useEffect(() => {
    load();
  },);

  return (
    <NavigationContainer>
      <OnboardingStack.Navigator initialRouteName={initialRouteName}>
        <OnboardingStack.Screen name="Onboarding" component=         {OnboardingScreen} />
        <OnboardingStack.Screen
          name="Login"
          component={LoginScreen}
          options={{ header: () => null }}
        />
        <OnboardingStack.Screen
          name='SignUp'
          component={SignUpScreen}
        />
        <OnboardingStack.Screen
          name='Home'
          component={AppTabsScreen}
        />
        <OnboardingStack.Screen
          name={'Loading'}
          component={LoadingScreen}
        />
      </OnboardingStack.Navigator>
    </NavigationContainer>
  );
}


Solution

  • You can use your state to check if key from storage is loaded:

    const [statusKeyLoaded, setStatusKeyLoaded] = useState(false)
    

    When your key is loaded set this state to true:

    let key = await AsyncStorage.getItem("launchStatusKey")
    setStatusKeyLoaded(true)
    

    Then render view only when you know your key is loaded:

    return (
       <>
        {statusKeyLoaded && (
        <NavigationContainer>
           ....
        </NavigationContainer> )}
       </>