kanzitelli / expo-starter

🦥 Expo Starter - Powered by Expo SDK, Navio (React Navigation), RN UI lib, MMKV, Mobx, Reanimated 2, Dark Mode, Localization, and much more.
https://starters.dev
403 stars 54 forks source link

Log In Screen #14

Closed ziv-caspi closed 2 years ago

ziv-caspi commented 2 years ago

What is the correct way of implementing a login screen in this template? I have tried storing the logged in user in a store, and using a conditional render in the RootNavigator but I am having errors.

// Root Navigator
export const RootNavigator: React.FC =  observer(({}) => {
  const {auth} = useStores();
  console.log('regenrated', auth.currentUser);
  if (auth.currentUser != null)
  {
    return genRootNavigator(TabNavigator, [modals.ExampleModal]);
  }
  else
  {
    return LoginStack();
  }
});
emrahc commented 2 years ago

Try to render conditional routes in the "genRootNavigator" function.

kanzitelli commented 2 years ago

Hey, it's not recommended to add any logic inside gen...Navigator functions and Navigators itself (which are located in src/screens/index.ts), they should be as dumb as possible.

Better way would be to describe AuthNavigator (for example) in src/screens/index.ts and toggle AuthNavigator and RootNavigator in src/app.tsx depending on auth state.

// src/screens/index.ts

export const AuthNavigator = (): JSX.Element =>
  genStackNavigator([screens.Login, screens.Registration, screens.ForgotPassword]);
// src/app.tsx

export const AppNavigator = observer(() => {
  useColorScheme();
  const {nav} = useServices();
  const {auth} = useStores();

  return (
    <>
      <StatusBar barStyle={getThemeStatusBarStyle()} backgroundColor={getThemeStatusBarBGColor()} />
      <NavigationContainer
        ref={nav.n}
        onReady={nav.onReady}
        onStateChange={nav.onStateChange}
        theme={getNavigationTheme()}
      >
        {!!auth.currentUser ? <RootNavigator /> : <AuthNavigator />}
      </NavigationContainer>
    </>
  );
});

Or there is also the other way - you can describe AuthNavigator as above and just show it as a modal without messing toggling navigators.

Whatever works better for you.

nykolaslima commented 2 years ago

@kanzitelli after the successful login, how can I redirect to a screen in the RootNavigator?

kanzitelli commented 2 years ago

hey @nykolaslima! Could you elaborate more on your use case? I have a possible solution in mind but maybe yours is something different.

nykolaslima commented 2 years ago

Thanks for the fast response @kanzitelli !

I'm pretty new to react/react native, so maybe it's quite simple to solve.

I've implemented your suggested solution and after the successful login I'm trying to redirect to the Main screen:

const loginResponse: SuccessfulLoginResponse = data?.loginUser;
const token: string = loginResponse.token;
const refreshToken: string = loginResponse.refreshToken;
const user: User = loginResponse.user;
auth.setLoggedUser(user, token, refreshToken);
nav.push('Main');

And I get the following error:

The action 'PUSH' with payload {"name":"Main"} was not handled by any navigator.

Do you have a screen named 'Main'?

If you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator.

The navigators were configured this way:

const TabNavigator = () => genTabNavigator([tabs.Main, tabs.WIP, tabs.Settings]);

export const AuthNavigator = (): JSX.Element => genStackNavigator([screens.Login]);

// Root Navigator
export const RootNavigator = (): JSX.Element =>
  genRootNavigator(TabNavigator, [modals.ExampleModal]);
<>
      <StatusBar barStyle={getThemeStatusBarStyle()} backgroundColor={getThemeStatusBarBGColor()}/>
      <NavigationContainer
        ref={nav.n}
        onReady={nav.onReady}
        onStateChange={nav.onStateChange}
        theme={getNavigationTheme()}
      >
        {!!auth.currentUser ? <RootNavigator /> : <AuthNavigator />}
      </NavigationContainer>
    </>

What am I missing here?

kanzitelli commented 2 years ago

@nykolaslima no problem! I just like checking GitHub on Sunday night 😁

So from what I can see, you don't need to do nav.push('Main') because <RootNavigator /> will automatically show tabs.Main navigator as it is the first element of the tabs array in TabNavigator.

Make sure that you set auth.currentUser in your auth.setLoggedUser(...) method.

Let me know how it goes!

nykolaslima commented 2 years ago

I tried this and if the app is reloaded (closing it and opening again) then the RootNavigator is shown with the expected tabs. But after clicking into the login button and setting the auth.currentUser the screen is not "reloaded" with the RootNavigator

kanzitelli commented 2 years ago

@nykolaslima is your AppNavigator wrapped with mobx’s observer(…) function?

nykolaslima commented 2 years ago

mobx’s observer

It worked with the observer in the AppNavigator:

export const AppNavigator = observer((): JSX.Element => {
  useColorScheme();
  const {nav} = useServices();
  const {auth} = useStores();

  return (
    <>
      <StatusBar barStyle={getThemeStatusBarStyle()} backgroundColor={getThemeStatusBarBGColor()}/>
      <NavigationContainer
        ref={nav.n}
        onReady={nav.onReady}
        onStateChange={nav.onStateChange}
        theme={getNavigationTheme()}
      >
        {!!auth.currentUser ? <RootNavigator /> : <AuthNavigator />}
      </NavigationContainer>
    </>
  );
});

Thank you very much @kanzitelli :)

kanzitelli commented 2 years ago

@nykolaslima awesome, glad it helped! :)