I have a react-native app that stores login credentials in a jwt. My logout function looks like this:
logOut={() => {
AsyncStorage.getAllKeys()
.then((keys) => AsyncStorage.multiRemove(keys))
.then(() =>
navigation.reset({
index: 0,
routes: [{ name: 'Login' }],
key: null,
}),
)
My StackNavigator (in App.jsx) looks like this:
<NavigationContainer >
<Stack.Navigator>
{valid_token ? (
consented ? (
<>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Nav" component={Nav} /> // Nav is the component with the login function
</>
): (
<>
<Stack.Screen name="ConsentForm" component={ConsentForm} />
</>
)
) : (
<>
<Stack.Screen name='Login'>
{(props) => <Login setExpired={setValidToken} setConsented={setConsented} />}
</Stack.Screen>
</>
)}
</Stack.Navigator>
</NavigationContainer>
valid_token
is set based on the value of the jwt, which is in async storage. I am clearing out the token in the logout function, however, App.jsx doesn’t see that. I also am not sure if I really have to pass the setValidToken
and setConsented
props throughout the whole app (the nav bar, which contains the logout, is on every screen). When I don’t pass props and run the code as is, I get this error:
The action 'RESET' with payload {"index":0,"routes":[{"name":"Login"}],"key":null} was not handled by any navigator.
I tried replacing the navigation.reset
part of the logout function with navigation.dispatch(StackActions.popToTop())
– this takes me to the Home page.
Is passing props throughout the whole app my only option?
2
Answers
The issue you’re facing is a common one when dealing with authentication and navigation in React Native. The problem arises because the navigation state isn’t being updated when the token is removed from AsyncStorage. Here are a few suggestions:
Centralize your authentication state: Instead of passing
setValidToken
andsetConsented
props throughout your app, consider using a centralized state management solution like Redux or React’s Context API. This way, you can update the authentication state from anywhere in your app and have it immediately reflected everywhere.Use an authentication flow: Consider setting up an authentication flow as suggested in the React Navigation documentation. This involves creating a separate stack navigator for authentication-related screens (like Login) and another for the main app screens. You would then conditionally render one or the other based on your authentication state.
Reset the navigation state correctly: The error message suggests that the ‘Login’ route doesn’t exist in your navigator when you’re trying to reset to it. Make sure that the route names you’re using with navigation actions correspond to the
name
props of yourScreen
components.Here’s an example of how you might set up your navigators:
In your logout function, you would then reset to the ‘Login’ screen like this:
This should correctly reset the navigation state and take you back to the login screen. Remember to replace
createStackNavigator
with whatever type of navigator you’re using (e.g.,createStackNavigator
,createBottomTabNavigator
, etc.)Do not manually navigate when using conditionally rendering screens. Logout should just invalidate a state and login screen will automatically appear. Use Context to manage the state instead of passing props. Here is a super simple example:
See Authentication flows for details.