React Navigation 6.x pressing back button takes you back to initial screen - react-native

I have just moved from React Native 5.x to 6.x and now my Navigation stack is giving me issues. When I navigate a few screens deep in my drawer navigator, and then press the back button on android (haven't tried IOS yes), it leads me right back to my first screen. My Navigation stack is as follows
<NavigationContainer theme={MyTheme}>
<Drawer.Navigator
initialRouteName="NewsFeed"
drawerContent={(props) => <SideNav {...props} />}
screenOptions={{ headerShown: true, header: (options) => <TopNav options={options} /> }}
>
<Drawer.Screen name="NewsFeed" component={NewsFeedScreen} />
<Drawer.Screen name="Post" component={PostScreen} />
<Drawer.Screen name="Users" component={UsersScreen} />
<Drawer.Screen name="User" component={UserScreen} />
...
</Drawer.Navigator>
</NavigationContainer>
I'm unsure what the issue is and haven't found any answers anywhere. Some say to wrap each screen in it's Stack navigator, others say it's a bad idea.

I am not sure if this is what you are asking for, but as for changes listed in the React Navigation Upgrading from 5.x help page:
The default value for backBehavior is now firstRoute for tabs and
drawer
and then:
To preserve old behavior, you can pass backBehavior="history" prop
to the navigators
So you can properly set backBehavior prop in your code like below:
<NavigationContainer theme={MyTheme}>
<Drawer.Navigator
initialRouteName="NewsFeed"
drawerContent={(props) => <SideNav {...props} />}
screenOptions={{ headerShown: true, header: (options) => <TopNav options={options} /> }}
backBehavior="history" // <-- ADDED PROP
>
...
</NavigationContainer>

Related

How to minimize React Native Navigation Modal?

How to minimize a modal within a Stack Navigator in React Native so that the model still shows as a small bar at the bottom of the screen and stays even when switching tabs (like in the pictures I attached).
Picture of Modal opened
Picture of Modal miminized
Currently I have built a Bottom Navigation Tab Bar and within this Tab Navigator I have a Stack Navigator where the Modal can be opened.
<Tab.Navigator initialRouteName="Session">
<Tab.Screen name="Social">{() => <Social />}</Tab.Screen>
<Tab.Screen name="History">{() => <History />}</Tab.Screen>
<Tab.Screen name="Session" options={{headerShown: false}}>
{() => (
<Stack.Navigator>
<Stack.Screen name="Start Session">
{() => <StartSession navigate={navigate} />}
</Stack.Screen>
<Stack.Screen
name="New Template"
options={{
presentation: 'containedModal',
}}>
{() => <AddTemplate />}
</Stack.Screen>
</Stack.Navigator>
)}
</Tab.Screen>
<Tab.Screen name="Activities">{() => <Activities />}</Tab.Screen>
<Tab.Screen name="Profile">
{() => <Profile setUser={setUser} setUserCreds={setUserCreds} />}
</Tab.Screen>
</Tab.Navigator>
You can achieve this using a bottom sheet instead of using a modal from react native navigation.
Something like:
https://www.npmjs.com/package/#gorhom/bottom-sheet

Disable animation for a custom header in React Navigation

I would like to disable the screen animation for the header part of the Stack Navigator.
I have a common custom Header defined in the Stack Navigator via screenOptions.
And have default animations for screen transitions.
I want to make sure the animation happens only to the screen and not to my header component.
Since the header will a static content.
I've also tried making the headerMode as screen and float but that did not help.
I wanted to see if there is a property similar to animationEnabled but for the header component.
<Stack.Navigator
screenOptions= {{
headerMode: 'screen',
animation: 'fade',
header: (props) =>
<Header {...props} />
}}>
// Rest of my screens
</Stack.Navigator>
What you could do is completely separate the header from your Navigator, and use a ref to control navigation from it. Something like this:
const App = () => {
const navigationRef = useNavigationContainerRef()
return (
<View>
<Text>This header won't animate!</Text>
<Text onPress={() => navigationRef.navigate('Home')}>Link</Text>
</View>
<NavigationContainer ref={navigationRef}>
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Other" component={OtherScreen} />
</Stack.Navigator>
</NavigationContainer>
)
}

Disabling gesture in react-navigation 5

I'm creating a project and Initially, it has two stack screens. SettingScreen and ChangePasswordScreen and the one drawer.
export const SettingStackScreen = ({ navigation }) => (
<SettingStack.Navigator>
<SettingStack.Screen
name="Settings"
component={SettingScreen}
/>
<SettingStack.Screen
name="ChangePassword"
component={ChangePasswordScreen}
/>
</SettingStack.Navigator>
);
app.js
<Drawer.Navigator
drawerContent={(props) => <DrawerContent {...props} />}
>
<Drawer.Screen name="Settings" component={SettingStackScreen} />
</Drawer.Navigator>
using this code Drawer is accessible on both screen but I want to access drawer only first screen of SettingStackScreen not on others screen.
I tried gestureEnabled but it disabling the drawer swipe gesture in the both screen.
give this a go:
<Drawer.Navigator
drawerContent={(props) => <DrawerContent {...props} />
edgeWidth={-1} // don't allow slide-to-open
>
<Drawer.Screen name="Settings" component={SettingStackScreen} />
</Drawer.Navigator>
from the docs:
edgeWidth
Allows for defining how far from the edge of the content view the
swipe gesture should activate.
This is not supported on Web.
If you go with this solution you're gonna need a burger menu or something that opens the drawer menu, something like:
<BurgerMenuButton onPress={() => navigation.toggleDrawer()} />

React native: How can I have multiple drawer navigator links point to screens within the same stack navigator

I am new to react native and I haven't seen this question asked by anyone or haven't found a way around this.
Using react navigation 5 with expo.
Currently I have a the following app structure:
Stack navigator inside of drawer navigator.
Example of page structure:
Drawer Navigator ( links ):
Home (RouteStack)
Screen 1
Screen 2
Screen 3
RouteStack( screens) :
Home ( initial route )
Screen 1
Screen 2
Screen 4
How can I get Screen 1/Screen 2 link in drawer navigator load RouteStack: Screen 1/Screen 2?
These links are provided to easily jump to the required screen.
Need some guidance on how to achieve this.
I have thought of the possibility of drawer inside of stack, but there are screens inside of drawer that may not be listed in the stack. Hence, went with stack inside of drawer.
I have also tried to do a navigation.navigate(route.name) inside of RouteStack
Sample code:
Drawer navigator:
<NavigationContainer>
<Drawer.Navigator drawerContent={(props, navigation) => <CustomDrawerContent {...props} {...navigation} />}>
<Drawer.Screen name="Home" component={RouteStack} />
<Drawer.Screen name="MyItems" component={RouteStack} />
<Drawer.Screen name="ContactRep" component={RouteStack} />
<Drawer.Screen name="Settings" component={SettingInfo} />
</Drawer.Navigator>
</NavigationContainer>
Stack navigator (RouteStack) looks like this:
<Stack.Navigator
initialRouteName="Home"
screenOptions={{ gestureEnabled: false, headerTitleAlign: 'auto' }}
// headerMode="float"
>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
title: '',
headerStyle: {
backgroundColor: '#fff',
},
headerTintColor: '#000',
headerTitleStyle: {
fontWeight: 'bold'
},
headerLeft: props => <HeaderLeftMenu {...props} />,
headerRight: props => <HeaderRightMenu {...props} />,
headerTitle: props => <HeaderTitle {...props} />
}}
/>
<Stack.Screen
name="ContactRep"
component={ContactRep}
options={{ headerTitle: props => <HeaderTitle {...props} /> }}
/>
<Stack.Screen
name="MyItems"
component={MyItems}
options={{ headerTitle: (props, navigation) => <HeaderTitle {...props} /> }}
/>
</Stack.Navigator>
Thanks in advance and help is appreciated.
Your method is fine. But to clarify your ideas I will give you an example.
Assume I have a main Drawer. In that drawer I can navigate to 2 different screens. Inside those screens, I can navigate and do diferent things (like going to sub-screens), but never go outside the drawer.
To do this, we would have to created nested navigators. This meaning, one type of navigator if going to be inside another one. In our case of example:
<Papa Drawer>
<Screen 1 component={StackSon1}>
<Screen 2 component={StackSon2}>
<Papa Drawer>
And then StackSon1, for example, will look like this:
StackSon = () => {
return (
<Stack.Navigator>
<Stack.Screen>
<Stack.Screen>
...
)
}
React Navigation will also handle every drawer separately, meaning that you don't have to worry about the user creating an infinite chain of open screens.
Also, remember that, when we Nest navigators using a function (like I did) we must use return (or the simplified version of return with just parenthesis)
Hope it helps.

Got both 'component' and 'children' props for the screen 'Search'. You must only pass one of them

I work on a react-native app and this project used react-navigation 4.x to navigate around the app.
I recently upgraded the project to 5.x of react-navigation and while trying to upgrade I ran into a problem. The problem is that my project has both a FooterNavigator and a DrawerNavigator, they both call on the same component.
We already figured out a way to fix the problem in react-navigation 4.x but the new version of react-navigation requires a name and a component for each Screen. Is there any way for me to have both the navigators at the same time or is it better to downgrade?
Image of the error
This is my FooterNavigator
const Tab = createBottomTabNavigator();
export const FooterNavigator = () => {
return (
<Tab.Navigator>
<Tab.Screen name="Search" component={Search}>
<Button>
<Icon name="magnify" type="MaterialCommunityIcons"/>
<Text style={footerStyle.footerText}>Zoeken</Text>
</Button>
</Tab.Screen>
<Tab.Screen name="Count" component={Count}>
<Button>
<Icon name="counter" type="MaterialCommunityIcons"/>
<Text style={footerStyle.footerText}>Tellen</Text>
</Button>
</Tab.Screen>
<Tab.Screen name="Identify" component={Identify}>
<Button>
<Icon name="file-question" type="MaterialCommunityIcons"/>
<Text style={footerStyle.footerText}>Herken</Text>
</Button>
</Tab.Screen>
<Tab.Screen name="Program" component={Program}>
<Button>
<Icon name="chip" type="MaterialCommunityIcons"/>
<Text style={footerStyle.footerText}>Wijzig</Text>
</Button>
</Tab.Screen>
</Tab.Navigator>
)
}
And this is my DrawerNavigator
export const RootNavigator = () => {
let DrawerScreens = [];
Routes.forEach(function (route) {
DrawerScreens.push(<Drawer.Screen name={route.name} component={route.component}/>)
});
return (
<Drawer.Navigator>
{DrawerScreens}
</Drawer.Navigator>
)
}
They are both called and rendered in my Layout.js
render() {
return (
<NavigationContainer>
<RootNavigator />
<FooterNavigator/>
</NavigationContainer>
)
}
Many thanks in advance !!
use this
<Stack.Screen name="Home" component={HomeScreen} />
instead of this
<Stack.Screen name="Home" component={HomeScreen}> </Stack.Screen>
solve your problem
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen}/>
<Stack.Screen name="Details" component={DetailScreen} />
</Stack.Navigator>
</NavigationContainer>
Just remove component prop from stack screen. if you are passing custom values through navigation stack
I get this error when I use a <Stack.Screen> and provide a component and a child to it, as the error mentions.
<Stack.Screen name="Home" component={Home}>
{props => <Home {...props} sampleProperty="XXXXXXXX" />}
</Stack.Screen>
removing this bit component={Home} on line1 fixes the error.