React navigation 5.x / React native – bottom-tabs navigation with same instance of component - react-native

I want to reuse the same instance of one component in two tabs (bottom bar tabs).
created with const Tab = createBottomTabNavigator();
Tab stack:
<Tab.Navigator
tabBarOptions={{
activeTintColor: Colors.tabs.active,
inactiveTintColor: Colors.tabs.inactive,
}}>
<Tab.Screen
name="NavigationMap"
component={Map}
options={{
tabBarLabel: 'Navigation',
}}
/>
<Tab.Screen
name="DiscoveryMap"
component={Map}
options={{
tabBarLabel: 'Discover',
}}
/>
<Tab.Screen
name="Other"
component={OtherComponent}
options={{
tabBarLabel: 'Other',
}}
/>
</Tab.Navigator>
I want to have the same behavior than in the Google Maps application on Android with the "Explore" and "Commute" tabs: stay in the same screen with a different state. I do not want to reload completely my map between the 2 tabs (and have independant zoom levels, center, ...).
Note: I cannot achieve that behavior with the tabPress method.

You can add focus listeners to both screens. Here, you can set the context or global state that can be accessed by the HomeNavigation component and change the behaviour.
<Tab.Screen
name="Home"
component={HomeNavigation}
listeners={{
focus: () => console.warn('focused 1'),
}}
/>
<Tab.Screen
name="Home2"
initialParams={{testing: true}}
component={HomeNavigation}
listeners={{
focus: () => console.warn('focused 2'),
}}
/>

Related

How can I hide the screen header but show my back button?

I would like to hide my screen header but still show the back button in my Stack Navigator? I have set screenOptions={{ headerShown: false }} in my Stack.Navigator, which hides both the screen header and back button. I would like to just hide the screen header.
Can someone please assist with this? Below is my Stack Navigator:
function SearchStack() {
return (
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="SearchScreen" component={SearchScreen} />
<Stack.Screen name="SearchListScreen" component={SearchListScreen} />
</Stack.Navigator>
);
}
In the tab navigator the stack is set as:
<Tab.Navigator screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {...})}>
<Tab.Screen name="Search" component={SearchStack} />
</Tab.Navigator>
This is what I'm currently seeing:
But this is what I would like to have with my Tab navigation bar still at the bottom for the search stack:
This is what I get using options={{headerMode:"none"}} in Stack.Navigator:
The below occurs when adding updating the Stack.Navigator to <Stack.Navigator screenOptions={{ headerTitle:"", headerTransparent:true }}> . How can add or move the back button to the top exactly like the 2nd image, which is achieved when not adding the Stack to the Tab.Screen so changing:
<Tab.Screen name="Search" component={SearchStack} />
to
<Tab.Screen name="Search" component={SearchScreen} />
but doing this causes the tab to not appear in the Search list screen.
The back button is part of the header, so you can't hide the header and keep the back button.
What you want to do is to hide other parts of the header except for the back button, which would be
Title, with headerTitle: ""
Background, with headerTransparent: true
for hide the back button in react-native, we can use property,
headerBackVisible:false this property only work on android
<Stack.Screen
options={{headerBackVisible: false}}
/>
example use of in Stack
const CustomerStack = () => {
return (
<Stack.Navigator>
<Stack.Screen
name="First"
component={First}
options={{headerShown: false}}
/>
<Stack.Screen
name="Third"
component={Third}
options={{headerTitle: '', headerTransparent: true}}
/>
</Stack.Navigator>
);
}
If you don't want the default header then use like this
screenOptions={{ headerShown: false }}
and write custom code for the header with back button in your component
(If your are using class component) Then
<TouchableOpacity onPress={()=>this.props.navigation.goBack()} style={{width:'100%', height:45, flexDirection:'row'}}> <Image source={require('back button image path')}/> </TouchableOpacity>
if you want header title too then,
<TouchableOpacity onPress={()=>this.props.navigation.goBack()} style={{width:'100%', height:45, flexDirection:'row'}}> <Image source={require('back button image path')}/> <Text>SearchListScren</Text> </TouchableOpacity>
Put this code at top of the component code under a container

React Navigation 5 : Implementing a custom header on a BottomTabNavigator

I am using a BottomTabNavigator with 2 screens but I also want to use a custom header, which I imported, to each one of them. I have tried set an option to the Tab.Navigator by adding a setOptions in it:
const Tab = createBottomTabNavigator();
export default function App() {
return(
<NavigationContainer >
<Tab.Navigator setOptions={{
headerTitle: <Header />
//</Header> was imported
}}>
<Tab.Screen
name="HomeScreen"
component={HomeScreen}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ color, size }) => (
<AntDesign name="home" color={Colors.amarelo} size={30} />
)
}}
/>
<Tab.Screen
name="GroupScreen"
component={GroupScreen}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ color, size }) => (
<AntDesign name="car" color={Colors.amarelo} size={30} />
)
}}
/>
</Tab.Navigator>
</NavigationContainer>
)
}
However, my attempt was unsuccessful. I read that docs for React-Navigation 5 but I haven't found how to implement a custom header on a BottomTabNavigator
Bottom Tab navigator does not have a header. To do this you have to use stack Navigator inside each tab of the bottom tab navigator. So you need to create a stack navigator that have "HomeScreen" as screen, same for GroupScreen. Then, in the bottom tab navigator use the stack navigators as component for tab.screen.
Than you can customize headers of bottom tab navigator.
I could post a short code if it helps you

Stack.Navigator fade-transition between Stack.Screens in React-native?

How can I add a transition effect to Stacked Screes in React-native?
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerShown: false,
}}
>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Stocks" component={StocksScreen} />
</Stack.Navigator>
</NavigationContainer>
Is there a default way to achieve a fadeIn / fadeOut effect?
The simplest way to achieve fade effect:
const forFade = ({ current }) => ({
cardStyle: {
opacity: current.progress,
},
});
If you want to apply fade effect for the entire navigator:
<Stack.Navigator
screenOptions={{
headerShown: false,
cardStyleInterpolator: forFade,
}}>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Stocks" component={StocksScreen} />
</Stack.Navigator>
Also you can apply cardStyleInterpolator for single screen via setting options:
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ cardStyleInterpolator: forFade }}/>
You can customize forFade function in order to achieve other effects, or also you can use some pre-made interpolators, as:
forHorizontalIOS
forVerticalIOS
forModalPresentationIOS
forFadeFromBottomAndroid
forRevealFromBottomAndroid
import { CardStyleInterpolators } from '#react-navigation/stack';
<Stack.Screen
name="Profile"
component={Profile}
options={{
cardStyleInterpolator: CardStyleInterpolators.forFadeFromBottomAndroid,
}}
/>;
More info here: https://reactnavigation.org/docs/stack-navigator/#animations
For React Navigation 6.xx you can use the animation option:
<Stack.Screen
name="Profile"
component={Profile}
options={{ animation: 'fade' }}
/>
Supported values:
"default": use the platform default animation
"fade": fade screen in or out
"flip": flip the screen, requires presentation: "modal" (iOS only)
"simple_push": use the platform default animation, but without shadow and native header transition (iOS only)
"slide_from_bottom": slide in the new screen from bottom
"slide_from_right": slide in the new screen from right (Android only, uses default animation on iOS)
"slide_from_left": slide in the new screen from left (Android only, uses default animation on iOS)
"none": don't animate the screen

What is the proper way of dealing with navigation to screens located in separate navigators directly in react navigator 5?

I have aan app scenario where I have a Bottom tabs navigator as my base navigator tab with Home, Products ... as my tabs:
<Tab.Navigator
screenOptions={{
headerShown: true,
}}
tabBarOptions={{
showLabel: false,
activeTintColor: MyColors.COLOR_ACCENT,
}}>
<Tab.Screen
name="Home"
component={HomeStack}
options={{
tabBarIcon: ({color, size}) => (
<Icon name="home" color={color} size={size} />
),
}}
/>
<Tab.Screen
name="Product"
component={ProductStack}
options={{
tabBarIcon: ({color, size}) => (
<Icon name="business-center" color={color} size={size} />
),
}}
/>
<Tab.Screen
name="Request"
component={MedRequest}
options={{
color: MyColors.COLOR_PRIMARY,
tabBarIcon: ({color, size}) => (
<Icon
name="near-me"
color={color}
size={35}
style={{transform: [{rotateZ: '20deg'}]}}
/>
),
}}
/>
<Tab.Screen
name="Reminder"
component={Reminder}
options={{
tabBarIcon: ({color, size}) => (
<Icon name="alarm" color={color} size={size} />
),
}}
/>
<Tab.Screen
name="Location"
component={LocationStack}
options={{
tabBarIcon: ({color, size}) => (
<Icon name="location-on" color={color} size={size} />
),
}}
/>
</Tab.Navigator>
Lets consider my first 2 screens from Bottom Tabs.
The first one is Home. It contains a list of top 5 popular products and a "view all" link which navigates it to the second tab products.
Each individual listed products are supposed to navigate to the product detail page.Since, the productDetail navigation is not defined in the bottom tabs navigator, I tried to resolve this by creating a new Stack navigator in home via homeStack which is as:
<Stack.Navigator
screenOptions={{
headerShown: false,
}}>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Notifications" component={Notifications} />
<Stack.Screen name="ProductDetail" component={ProductDetail} />
<Stack.Screen name="AuthStack" component={AuthStack} />
<Stack.Screen name="BlogStack" component={BlogStack} />
<Stack.Screen name="BlogDetail" component={BlogDetail} />
<Stack.Screen name="Cart" component={CartStack} />
</Stack.Navigator>
Now that we have the productDetail navigator in handler, I am able to navigate to product detail.
Similarly, the product bottom tab has another stack navigator as ProductStack on top which helps in navigation to its various links. It is as:
<Stack.Navigator
screenOptions={{
headerShown: false,
}}>
<Stack.Screen name="Product" component={Product} />
<Stack.Screen name="CartStack" component={CartStack} />
<Stack.Screen name="ProductDetail" component={ProductDetail} />
</Stack.Navigator>
My main concern here is that I have been including the ProductDetail and CartStack as an element of navigators in more than one places and I have a feeling that I'm not doing this right.
Also can this multilevel stacking of navigators lead to a performance issue?
Also the cartStack I access when directly navigating to productDetail from home screen causes the disappearance of the bottom tabs.
Am I handling the situation totally wrong here?? Is there an easier way of doing this, that hasn't crossed my mind?
So it depends on which tab you want to stay on, if you want to stay on the home tab you can leave it in the home stack. If you want to go to the products tab -> product details page so when they go back/dismiss it will go back to the root screen of the products tab then you can do something like this to navigate to nested screens:
navigation.navigate('Product', { screen: 'ProductDetail' });
I think you should put your ProductDetail and CartStack and your BottomTabContainer in a Stack.Navigator, then you can easily navigate to ProductDetail or CartStack from anywhere in your BottomTabNavigator
Something like this:
<Stack.Navigator
screenOptions={{
headerShown: false,
}}>
<Stack.Screen name="TabNavigator" component={YourTabComponent} />
<Stack.Screen name="CartStack" component={CartStack} />
<Stack.Screen name="ProductDetail" component={ProductDetail} />
</Stack.Navigator>
then you can remove your CartStack and ProductDetail out of HomeStack and ProductStack.

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.