I have a login screen which I have placed in stack. After user logs in successfully he is redirected to home screen which is a drawer screen. One of the options of drawer screen is logout, so on click of it user should be logged out. Following is my code for logout screen. I am just showing a progress bar of logout screen in ui but in useEffect hook, I am calling the following method
navigation.navigate({index: 0, routes: [{name: LOGIN_SCREEN}]});
but I get an error saying You need to specify name or key when calling navigate with an object as the argument and I am redirected to home screen. when I restart my app completely then only it moves to login screen. I am passing the right value for name key.
My Navigation stack looks something as follows
<Stack.Navigator>
<Stack.Screen
name={LOGIN_SCREEN}
component={LoginScreen}
options={{headerShown: false}}
/>
<Stack.Screen
name={HOME_STACK_SCREEN}
component={DrawerStack}
options={{headerShown: false}}
/>...
My drawer component as follows
<Drawer.Navigator
drawerStyle={{backgroundColor: BLUE_COLOR_1}}
drawerContentOptions={{labelStyle: {color: '#FFF'}}}>
<Drawer.Screen
name={HOME_SCREEN}
component={Home}
options={{
...
}}
/>
<Drawer.Screen
name={LOGOUT_SCREEN}
component={Logout}
options={{
...
}}
/>
In react-navigation v5. You can reset navigation like this
import { CommonActions } from "#react-navigation/native";
this.props.navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [{ name: "LOGIN_SCREEN" }],
})
);
If you want to reset then you need to use reset, not navigate:
navigation.reset({
routes: [{ name: LOGIN_SCREEN }]
});
Related
I'm using React Navigation 6.x's linking with Expo so that when a user clicks on a notification they are directed to the appropriate part of my application to interact with the new information. When my app is backgrounded (running in the background) and a user clicks on a notification they are redirected to the screen they need to be at, which works perfectly fine. However, when the app is killed and the user clicks on a notification, they are taken directly to the screen for which the url is provided and they cannot press back to navigate elsewhere in my application. I tried to resolve this by using the initialRouteName prop like is shown in the docs (link: https://reactnavigation.org/docs/configuring-links/#rendering-an-initial-route), but I cannot get it to work. For further clarification, when I mentioned above that I am able to get linking working it is in relation to the direct SettingsScreen, AddFriendScreen, and MessagingScreen links. What I cannot get working is the specific block of code inside the liking object that starts with HomeScreen. What I believe may be causing the issue is that I am trying to set my initialRoute as a screen within HomeScreen's Tabs.Navigator and then trying to route to a screen within my Stack.Navigator. However, the docs show that this is possible (link: https://reactnavigation.org/docs/configuring-links/#rendering-an-initial-route).
My code:
const linking = {
prefixes: [prefix],
config: {
screens: {
HomeScreen: {
initialRouteName: "Chats",
screens: {
AddFriendScreen: "addFriend",
CreateChatScreen: "createChatScreen",
Friends: "friends",
MessagingScreen: 'messagingScreen/:chatRoomId'
}
},
SettingsScreen: "SettingsScreen",
AddFriendScreen: "AddFriendScreen",
MessagingScreen: 'MessagingScreen/:chatRoomId'
},
}
};
<NavigationContainer linking={linking} theme={MyTheme} >
<Stack.Navigator>
{!authState.value ?
<>
<Stack.Screen name="LoginScreen" component={LoginScreen} />
<Stack.Screen name="SignUpScreen" component={SignUpScreen} />
<Stack.Screen name="ForgotPasswordScreen" component={ForgotPasswordScreen} />
</>
:
<>
<Stack.Screen name="HomeScreen" component={HomeScreen} />
<Stack.Screen name="MessagingScreen" component={MessagingScreen} />
<Stack.Screen name="SettingsScreen" component={SettingsScreen} />
<Stack.Screen name="CreateChatScreen" component={CreateChatScreen} />
<Stack.Screen name="AddFriendScreen" component={AddFriendScreen} />
</>
}
</Stack.Navigator>
</NavigationContainer>
const HomeScreen = () => {
return (
<Tabs.Navigator>
<Tabs.Screen name="Chats" component={ChatScreen} />
<Tabs.Screen name="Friends" component={FriendsScreen} />
<Tabs.Screen name="Profile" component={ProfileScreen} />
</Tabs.Navigator>
)
}
Hmm, I would put any screen that I would like to access in multiple navigators at the root level so that they can both reach it.
For my own project, I have a root stack with a dedicated auth stack and an app/home stack (which is a tab nav like your HomeScreen). And outside that I have all my modal and root screens that I'd like other navigators to access (Because I really have two Home tab navigators the user can switch between.)
Idk if putting all of your screens listed after HomeScreen outside of that object will help your situation, but you can try that.
I have a React Native project that uses react-navigation v6. This is the navigation structure:
const { user } = userContext;
<NavigationContainer>
{user === null ? (
<AuthStack.Navigator
initialRouteName={"SignIn"}
screenOptions={{ headerShown: false }}
>
<AuthStack.Screen name="SignIn" component={SigninScr} />
<AuthStack.Screen name="SignUp" component={SignupScr} />
<AuthStack.Screen
name="EmailVerification"
component={EmailVerificationScr}
/>
</AuthStack.Navigator>
) : (
<Tab.Navigator
initialRouteName={'HomeStack'}
screenOptions={{ headerShown: false}}
>
<Tab.Screen name={'HomeStack'} children={()=><HomeStack />}/>
<Tab.Screen name={'DiscoverStack'} children={()=><DiscoverStack />}/>
<Tab.Screen name={'CalendarStack'} children={()=><CalendarStack />}/>
<Tab.Screen name={'ProfileStack'} children={()=><ProfileStack />}/>
</Tab.Navigator>
)}
</NavigationContainer>
Essentially, there are two stacks:
Auth stack
Signin screen, signup screen, etc...
Regular stack
4 nested stacks (home stack, discover stack, calendar stack, profile stack)
I am using React Context to switch from the auth stack to the regular stack (or regular stack to auth stack)
The problem is that when the user logs off and signs back in, their stack was never reset and they are directed to the screen where they logged off. For example, user A logs in and goes to the profile screen, then they press log out. User A now logs back in, and instead of being sent to the home screen, they are sent back to the profile screen.
I want the navigation state of the regular stack to be reset when a user logs off. I have tried doing this, but it doesn't work (user still gets sent to the profile screen):
const { setUser } = this.context;
const { navigation } = this.props
navigation.reset({
index: 0,
routeNames: ['Home'],
routes: [{ name: 'Home' }],
});
setUser(null);
How can I completely reset the stack when switching stack for authentication flow?
For reference, this is what one of the stacks in the regular stack would look like:
const HomeStack = () => (
<Stack.Navigator screenOptions={{
headerTintColor: 'white',
headerTitleStyle: { color: 'white' },
headerStyle: { backgroundColor: colors.primary0 },
}}
>
<Stack.Screen name={'HomeScr'} component={HomeScr} />
...
</Stack.Navigator>
);
Actual behavior:
Expected behavior:
I have an app with multiple stack navigators (nested). The docs say that you navigate to a nested screen like:
navigation.navigate('Root', { screen: 'Settings' });
However, in my situation I don't want to allow the user to go back so I want to use a reset/replace action. How would you do that?
The documentation says how to do a reset to a route, but doesn't give info on how to specify the screen e.g.
navigation.reset({
index: 0,
routes: [{name: 'Root'}], //Where to put screen?
});
EDIT Here is my setup
On the top level I have 3 screens in a stack:
<Stack.Navigator
initialRouteName="HiddenScreen"
screenOptions={{headerShown: false}}>
<Stack.Screen
name="HiddenScreen"
component={HiddenScreen}
/>
<Stack.Screen
name="VideoConferenceIncoming"
component={VideoConferenceIncoming}
}}
/>
<Stack.Screen name="CreateUser" component={CreateUser} />
</Stack.Navigator>
Now the CreateUser Screen has a stack inside it too:
<Stack.Navigator
initialRouteName={initialRoute}
screenOptions={{
headerShown: false,
}}>
<Stack.Screen name="Step1" component={CreateUserStep1} />
<Stack.Screen name="Step2" component={CreateUserStep2} />
<Stack.Screen name="UserRegistered" component={UserRegistered} />
<Stack.Screen name="ChangePassword" component={ChangePassword} />
<Stack.Screen name="WaitingRoom" component={WaitingRoom} />
</Stack.Navigator>
Let's say I am currently inside the VideoConferenceIncoming screen. I want to navigate to the CreateUser>Waiting Room screen. However, I do not want the allow the user to go back.
Currently I have this solution which is not quite right:
navigation.reset({
index: 0,
routes: [{name: 'CreateUser'}],
});
navigation.navigate('CreateUser', {
screen: 'WaitingRoom',
params: {queuePosition: qPos, ticketNumber: ticketNumber},
});
It's not right because the user from the WaitingRoom screen can still go back a step.
The documentation here tells you how to do it. But can be a bit difficult to understand if you are new to react-navigation and how it works.
What it says is that you can now set the state of the nested navigator when using reset. So you can specify the specific screen you want to navigate to in the navigator state that you are setting.
So in your case, resetting would be like below.
navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [
{
name: 'CreateUser',
state: {
routes: [{name: 'WaitingRoom'}],
},
},
],
}),
);
I am creating a nested navigation container in react-native and the stack looks like this:
-Main Navigation Container:
- Home
- Market Navigation Container:
- Market
- Cart
- About
When I go to home or about and go back, it works properly. However, when I go back from Market or cart (Which I expect to go to the Home page) it shows an error saying:
The action 'POP' with payload {"count":1} was not handled by any navigator.
Is there any screen to go back to?
This is a development-only warning and won't be shown in production.
This is my code for the main navigation container:
<NavigationContainer independent={true}>
<Stack.Navigator>
<Stack.Screen options={myOptions} name="Home" component={Home} />
<Stack.Screen
options={{ headerShown: false }}
name="MarketNavigation"
component={MarketNavigation}
/>
<Stack.Screen options={myOptions} name="About" component={About} />
</Stack.Navigator>
</NavigationContainer>
And this is my code for the market navigation:
<NavigationContainer ref={navigationRef} independent={true}>
<Stack.Navigator>
<Stack.Screen
options={myOptions}
name="Market"
component={Market}
/>
<Stack.Screen
options={myOptions}
name="Cart"
component={Cart}
/>
</Stack.Navigator>
</NavigationContainer>
I faced this when navigating to nested navigator using "screen" option like this:
navigation.navigate('Root', {
screen: 'Settings'
})
;
As mentioned in the documentation:
By default, when you navigate a screen in the nested navigator, the
specified screen is used as the initial screen and the initial route
prop on the navigator is ignored.
To solve this you should use "initial: false" like so:
navigation.navigate('Root', {
screen: 'Settings',
initial: false,
});
Could you add in the code where you navigate from Home to MarketNavigation and back?
I am using React-Navigation v 5.0.1, I have a Drawer navigator nested inside Stack navigator that looks like this:
MainStack.js
function MainStack() {
return(
<Stack.Navigator>
<Stack.Screen name="Splash" component={Splash} />
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="HomeDrawerStack" component={HomeDrawerStack} />
</Stack.Navigator>
)
}
HomeDrawerStack.js
function HomeDrawerStack() {
return (
<Drawer.Navigator>
<Drawer.Screen name="Home" component={Home} />
</Drawer.Navigator>
)
}
When I tap a logout button on Home screen, how do I navigate to Login screen and reset / clear all other screens? (so it triggers the componentWillUnmount on other screens)
This code will navigate to Login Screen after clearing the stack. so that back button or back swipe will not work to navigate to HomeDrawerStack
navigation.reset({
index: 0,
routes: [{ name: "Login" }],
});
if I share how I handled it, it is like, I am sharing my code snippet as png here, so what I have done is appended Navigator with redux, and I use to change my stack or replace my stack by dispatching event to store attached to Navigator.