I am working on a project with another developer and we're at an impasse on how the authentication flow should go. We use RTK for state management. In the EntryPoint.tsx
, here's my approach:
export default function EntryPoint({ layoutHandler }: EntryPointProps) {
const { isDarkMode, themeColors } = useContext(ThemeContext);
const { accessToken } = useSelector((state:RootState) => state.auth)
return (
<>
<StatusBar
animated
backgroundColor={themeColors['neutral-00']}
barStyle={isDarkMode ? 'light-content' : 'dark-content'}
/>
<View
onLayout={layoutHandler}
style={[
globalStyles.container,
{
backgroundColor: themeColors['neutral-00'],
paddingBottom:
Platform.OS === 'android' ? styleGuide.layout.spacing.md : 0,
},
]}
>
{!accessToken ? <AuthNavigator /> : <MainNavigator />}
</View>
</>
);
}
In this approach, during logout, all that's needed is to remove/destroy accessToken and you'll be sent to the navigator stack that contains screens for authentication (OnBoarding, Login, Verify Login)
Here's my colleague's approach
export default function EntryPoint({ layoutHandler }: EntryPointProps) {
const { isDarkMode, themeColors } = useContext(ThemeContext);
const authState = store.getState().auth as AuthStateType;
const { isOnboarded } = authState;
return (
<>
<StatusBar
animated
backgroundColor={themeColors['neutral-00']}
barStyle={isDarkMode ? 'light-content' : 'dark-content'}
/>
<View
onLayout={layoutHandler}
style={[
globalStyles.container,
{
backgroundColor: themeColors['neutral-00'],
paddingBottom:
Platform.OS === 'android' ? styleGuide.layout.spacing.md : 0,
},
]}
>
{!isOnboarded ? <OnboardingNavigator /> : <AuthNavigator />}
</View>
</>
);
}
Basically, he's now rearranged the navigator stacks such that OnBoardingNavigator
stack contains only Login & AuthNavigator stack. Do note that the AuthNavigator
now contains Login screen again and the the MainNavigator. Logout now works in such a way that after accessToken is removed, we navigate back to Login screen.
Reason for his approach is he doesn't want to use useSelector
as subscribing to the store is costly and will lead to unknowns and unpredictability.
I seriously disagree with this as I believe the cost of subscription isn't worth refactoring all the navigation stacks which now mixes multiple screens in stacks they do not belong in. Simply using useSelector
will make the app React . However, He says reactivity comes at a cost.
What is the best approach/practice in this case?
Redux maintainer here.
Please don't use store.getState()
in your component like that ever.
If your store changes in the background, the component will not rerender with a new value. If you write your selector correctly, it will only rerender when the selector value changes.
So you can optimize here, but should keep the useSelector
call.
const isOnboarded = useSelector((state:RootState) => state.auth.accessToken.isOnboarded)
is a lot better.