Search code examples
javascriptreact-nativereact-navigation-v5

Auth with React Navigation V5, getting error when click button can't direct


i need a help, i created the auth with react navigation v5 in react native, the auth is working, but when i login with navigation.navigate('Beranda') in login form, i got the error, how to fix the error like this and here's my code code function for login

  const [body, setBody] = useState({
    username: '',
    password: '',
  });

  const _handleSubmit = () => {
    if (body.username === 'admin' && body.password === 'admin123') {
      AsyncStorage.setItem('username', 'admin');
      navigation.navigate('Beranda');
    } else {
      Alert.alert('Login Gagal');
    }
  };

and here my code for navigation

const HomeStackScreen = () => {
  return (
    <HomeStack.Navigator initialRouteName="Daily Transaction">
      <HomeStack.Screen name="DailyTransaction" component={DailyTransaction} />
      <HomeStack.Screen
        name="DetailTransaction"
        component={DetailTransaction}
      />
    </HomeStack.Navigator>
  );
};

const CashierStack = createStackNavigator();
const CashierStackScreen = () => {
  return (
    <CashierStack.Navigator initialRouteName="Menu">
      <CashierStack.Screen name="Menu" component={Menu} />
      <CashierStack.Screen name="DetailMenu" component={DetailMenu} />
      <CashierStack.Screen name="Cart" component={Cart} />
    </CashierStack.Navigator>
  );
};

const AuthStack = createStackNavigator();
const AuthScreenStack = () => {
  return (
    <AuthStack.Navigator headerMode="none">
      <AuthStack.Screen name="Login" component={Login} />
    </AuthStack.Navigator>
  );
};

const MenuBottom = createBottomTabNavigator();
const MenuBottomNav = () => {
  return (
    <MenuBottom.Navigator
      screenOptions={({route}) => ({
        tabBarIcon: ({focused, color, size}) => {
          if (route.name === 'Transaksi') {
            if (focused) {
              return (
                <Image
                  source={require('../../../assets/icons/wallet-gold.png')}
                  // eslint-disable-next-line react-native/no-inline-styles
                  style={{width: 25, height: 25}}
                />
              );
            } else {
              return (
                <Image
                  source={require('../../../assets/icons/wallet-white.png')}
                  // eslint-disable-next-line react-native/no-inline-styles
                  style={{width: 25, height: 25}}
                />
              );
            }
          } else if (route.name === 'Cashier') {
            if (focused) {
              return (
                <Image
                  source={require('../../../assets/icons/cash-gold.png')}
                  // eslint-disable-next-line react-native/no-inline-styles
                  style={{width: 25, height: 25}}
                />
              );
            } else {
              return (
                <Image
                  source={require('../../../assets/icons/cash-white.png')}
                  // eslint-disable-next-line react-native/no-inline-styles
                  style={{width: 25, height: 25}}
                />
              );
            }
          }
        },
      })}
      tabBarOptions={{
        activeTintColor: '#ffd700',
        inactiveTintColor: '#fff',
        style: {
          backgroundColor: '#000',
        },
      }}>
      <MenuBottom.Screen name="Transaksi" component={HomeStackScreen} />
      <MenuBottom.Screen name="Cashier" component={CashierStackScreen} />
    </MenuBottom.Navigator>
  );
};

const BerandaStack = createStackNavigator();
const BerandaScreen = () => {
  return (
    <BerandaStack.Navigator headerMode="none">
      <BerandaStack.Screen name="Beranda" component={MenuBottomNav} />
    </BerandaStack.Navigator>
  );
};

// const Stack = createStackNavigator();

const Main = () => {
  const [Loading, setLoading] = React.useState(true);
  const [token, setToken] = React.useState(null);
  React.useEffect(() => {
    const retrieveData = async () => {
      try {
        const valueString = await AsyncStorage.getItem('username');
        // Other set states
        setToken(valueString);
      } catch (error) {
        console.log(error);
      }
    };
    retrieveData();
  }, []);

  React.useEffect(() => {
    setTimeout(() => {
      setLoading(false);
    }, 4000);
  }, []);

  if (Loading) {
    return <Splash />;
  }
  return (
    <NavigationContainer>
      {token ? <BerandaScreen /> : <AuthScreenStack />}
    </NavigationContainer>
  );
};

export default Main;

here's the error click here

thank you for helping me before.


Solution

  • The reason why you are getting that if because the screen is not part of the navigation. The easiest way to fix this is to unconditionally render all routes

    return (
        <NavigationContainer>
          <AuthScreenStack/>
          <BerandaScreen/> 
        </NavigationContainer>
      );
    

    This will always render the AuthScreenStack first. If you want to keep the user logged in (check localStorage for token), You will need to add logic to your AuthScreenStack to redirect to the BarandaScreen stack if the token exists already.

    For automatically redirecting from the AuthScreenStack to BarandaScreen if the token exist, you can add the following to your AuthScreenStack:

    React.useEffect(() => {
        const retrieveData = async () => {
          try {
            const valueString = await AsyncStorage.getItem('username');
            // Other set states
            // maybe you want to validate it first
            if (valueString) navigation.navigate('Beranda');
          } catch (error) {
            console.log(error);
          }
        };
        retrieveData();
      }, []);
    

    This code runs only once when the component mounts. Get the token from the local storage, then navigates to the Beranda screen.