Oğulcan Karayel
Oğulcan Karayel

Reputation: 425

Navigation between different screens in react native

I've been working on a react native app. The app contains onboarding and other screens. I want to display the onboarding screen if user opens the app first time,if this is not the case the user must be welcomed by login screen

const LoadNavigation = () => {
  const { isFirst } = useIsFirstLaunch();

  return isFirst === null ? (
    <AppLoading />
  ) : (
    <AppStack.Navigator headerMode="none">
      {isFirst ? (
        <AppStack.Screen name="Onboarding" component={Onboarding} />
      ) : (
        <AppStack.Screen
          name="Authentication"
          component={AuthenticationNavigator}
        />
      )}
    </AppStack.Navigator>
  );
};

export default LoadNavigation;

export const AuthenticationNavigator = () => {
  return (
    <AuthenticationStack.Navigator headerMode="none">
      <AuthenticationStack.Screen name="Login" component={Login} />
    </AuthenticationStack.Navigator>
  );
};

This works but when I try to navigate from onboarding screen to login screen it gives me an error.

navigation.navigate("Authentication",{screen:"Login"})

Also I don't want to go back from login screen to onboarding screen when I press the back button on android(it must exit the app) if the user opens the app first time

Error like this

"The action 'NAVIGATE' with payload {"name":"Authentication","params":{"screen":"Login"}} was not handled by any navigator."

EDIT: I've added AuthenticationNavigator in isFirst condition as well. But this time if the "isFirst" whether is true or false ,it shows me the login page as well

 return (
    <AppStack.Navigator headerMode="none">
      {isFirst ? (
        <>
          <AppStack.Screen name="Onboarding" component={Onboarding} />
          <AppStack.Screen
            name="Authentication"
            component={AuthenticationNavigator}
          />
        </>
      ) : (
        <>
          <AppStack.Screen
            name="Authentication"
            component={AuthenticationNavigator}
          />
        </>
      )}
    </AppStack.Navigator>
  );
};

Upvotes: 0

Views: 527

Answers (2)

Arif Arifi
Arif Arifi

Reputation: 1502

This is how I did:

export default function App() {
  const [completedOnboarding, setCompletedOnboarding] = useState(true);
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  const isFirstTime = async () => {
    try {
      const value = await AsyncStorage.getItem('first_time');
      if (value === null || value === 'true') {
        setCompletedOnboarding(false);
      } else if (value === 'false') {
        setCompletedOnboarding(true);
      }
    } catch (error) {
      console.log({error});
    }
  };

  const onDone = async () => {
    try {
      await AsyncStorage.setItem('first_time', 'false');
      setCompletedOnboarding(true);
    } catch (error) {}
  };

  useEffect(() => {
    isFirstTime();
  }, []);

  return (
    <>
      {!completedOnboarding ? (
        <OnBoarding onDone={onDone} />
      ) : (
        <NavigationContainer>
          <Stack.Navigator screenOptions={{headerShown: false}}>
            {!isLoggedIn ? (
              <Stack.Screen
                name="Auth"
                component={Auth}
              />
            ) : (
              <Stack.Screen name="Home" component={Home} />
            )}
          </Stack.Navigator>
        </NavigationContainer>
      )}
    </>
  );
}

Upvotes: 1

oaamer
oaamer

Reputation: 26

At the point in time when your onboarding screen is mounted, the login one does not exist in the navigator hierarchy due to the conditional rendering. So you cannot navigate from within the Onboarding screen programmatically and this error is thrown.

In order to fix this you should use conditional routing exclusively as demonstrated in the docs here. You should use an effect to set up this initial state depending on whether the user is logged in/out, onboarding needed or not, etc. This depends on your auth/local state management setup.

EDIT: This should also solve the back button on Android, since conditional routing should eliminate any previous screens in the stack if you are setting it up correctly in an effect or similar.

Upvotes: 0

Related Questions