kanzitelli / rnn-starter

🤹 React Native Starter - Powered by cli-rn, React Native Navigation, Expo Modules, RNN Screens, RN UI lib, MMKV, Mobx, Reanimated 2, Dark Mode, Splash Screen, Localization, Notifications, Permissions, and much more.
https://starters.dev
MIT License
549 stars 72 forks source link

What is the best practice with rnn-screens to handle Authentication States? #86

Closed anttyc closed 2 years ago

anttyc commented 2 years ago

Hi, hope it's ok that I post here and thank you for taking the time to read this. Love what you've done here, but I can't figure out what would be the best way to handle the change in Auth States.. e.g

isLoading -> Show Splash Screen
isAuthenticated -> Show Main Screen Stack
!isAuthenticated -> Show Log In Screen Stack

I'd normally handle this in App.tsx with RNN, e.g

useEffect(()=>{
  authService.onAuthChange(()=>{
    ...
    isAuthenticated = true;  // Updates based on auth service
  })
}, [isAuthenticated])
...
<Stack.Navigator>
{isAuthenticated ? 
      <Stack.Screen name="SignIn" component={SignInScreen} />
    ) : (
      <Stack.Screen name="Home" component={HomeScreen} />
    )}
</Stack.Navigator>

But it isn't clear to me how to do this with registerRootComponent. I've successfully (hackily) used screens.N.setRoot(AuthStack) and screens.N.setRoot(MainTabsApp) to switch from one to another, but I wanted to know if you have a better way?

kanzitelli commented 2 years ago

Hey @anttyc!

RN and RNN have a bit different way of building navigation, so it might be hard to achieve the exact same way in RN and RNN.

Your "hack" is actually the way to go as it's done in rnn-screens (here).

What I usually do with RNN in this case, I show my main app (let's say it's a tab based app) and then on the first screen in useEffect, I check if a user is not authed then I do something like nav.show('Auth') so the modal is being shown.

The other way would be to start the app with a blank screen (let's say, AuthStateScreen) where you check on the auth state in useEffect and depending on it, you do screens.N.setRoot(Auth) or screens.N.setRoot(MainApp).

Let me know how it goes!

anttyc commented 2 years ago

Awesome! Your second suggestion is how I ended up doing it, just wanted to make sure I wasn't missing anything. Let me try your first suggestion as that seems more elegant.

Thanks so much @kanzitelli for the quick and detailed reply.

Yasir5247 commented 1 year ago

@kanzitelli why not expose start function with rnn-screens. so in app.tsx call the start() method in the navigation. so in this case based on the users auth logic he can show authStack or TabStack. so the logic will be in navigation service not in some screen right. just my thoughts

app.tsx

nav.start();

services/navigation/index.ts

  start = async (): PVoid => {
    const token = await AsyncStorage.getItem('@token');
    token ? await this.checkLoginProccesAndStartTabs() : await this.startOneScreenApp();
  };
kanzitelli commented 1 year ago

hey @Yasir5247! thanks for the idea! I am going to merge rnn-screens to rn-navio, so Navio will become a universal (with the same API for rnn and react-navigation) navigation library. And I will take your thoughts into the consideration.

Yasir5247 commented 1 year ago

hi @kanzitelli, thank you. btw were you able to solve https://github.com/kanzitelli/expo-starter/issues/27 in rn-navio?

kanzitelli commented 1 year ago

@Yasir5247 it's impossible to achieve exactly the same effect with react-navigation as we could do with React Native Navigation. The reason is that react-navigation doesn't use native tab bar controller under the hood. That's why the only way to do that with react-navigation (and Navio) is to push another stack over the tabs. But as you already faced the problems with back button (only on iOS tho), it's not the best solution. Idk, I would recommend maybe showing your product screen as a modal? I think it's better UX + easier to implement with Navio :)