Using both DrawerNavigator and BottomTabNavigator with the same screens - react-native

I'm writing a React Native app, while using react-navigation package for navigating through the app screens.
On my app's home screen, there is a bottom tab bar with about 4-5 buttons, each leading to a different screen. Besides that, all of my app's screens contain a navigation drawer that leads to the rest of the screens. All the screens listed on the bottom tab bar are included in the navigation drawer as well.
App.js:
const App = () => {
return (
<NavigationContainer>
<DrawerNavigator />
</NavigationContainer>
)
}
DrawerNavigator.js:
const DrawerNavigation = createDrawerNavigator();
const DrawerNavigator = () => {
return (
<DrawerNavigation.Navigator>
<DrawerNavigation.Screen
name="ScreenA"
component={BottomTabNavigator} />
<DrawerNavigation.Screen
name="ScreenB"
component={ScreenB} />
<DrawerNavigation.Screen
name="ScreenC"
component={ScreenC} />
</DrawerNavigation.Navigator>
)
}
BottomTabNavigator.js:
const BottomTabNavigation = createBottomTabNavigator();
const BottomTabNavigator = () => {
return (
<BottomTabNavigation.Navigator>
<BottomTabNavigation.Screen
name="ScreenA"
component={ScreenA} />
<BottomTabNavigation.Screen
name="ScreenB"
component={ScreenB} />
</BottomTabNavigation.Navigator>
)
}
My question is how can I sync between them?
Let's say on the navigation drawer I have ScreenA, ScreenB, and ScreenC, while on the bottom tab bar I have only Screen A and Screen B. I want to click on ScreenB in the drawer, and have ScreenB selected as well on the tab bar, and vice versa, clicking on ScreenB on the tab bar and have it selected too on the drawer.
Is such thing possible? How would you implement it?

Related

How can I redirect from StackNavigator screen to BottomTabNavigator screen

I'm working on an app in React-Native. How I'm trying to achieve this is by using a SignUpCompleted Flag and checking if its true/false to decide if the page should navigate to the next signup screen or just to the homepage. I have 3 screens as part of the sign-up process that I only want to be shown the 1st time the app opens. I have the 3 screens in a StackNavigator and I'm trying to navigate from the last StackNavigator screen to a BottomTabNavigator screen. Sadly I get the following error:
The action 'NAVIGATE' with payload {"name":"HomeStack"} was not handled by any navigator.
My current setup is as follows:
SignUpStack
const SignUpStack = createStackNavigator();
export default function SignUpStackScreen() {
const [signUpCompleted, setSignUpCompleted] = useState(false);
return (
<SignUpStack.Navigator initialRouteName="Welcome" screenOptions={{ headerShown: false }}>
<SignUpStack.Screen name="Welcome" component={WelcomeScreen} initialParams={{signUpCompleted}} />
<SignUpStack.Screen name="Department" component={ChooseDepartment} initialParams={{signUpCompleted}} />
<SignUpStack.Screen name="InputName" component={InputName} initialParams={{signUpCompleted, setSignUpCompleted}}/>
</SignUpStack.Navigator>
);
}
From the InputName component I try to redirect to a BottomTabNavigator Screen called homename
The redirect code is as follows: - in InputName component
<TouchableOpacity
style={[styles.shadow]}
onPress={() => {navigation.navigate("HomeName"); setSignUpCompleted(true)}}
>
The BottomTabNavigator is as follows: - I'm trying to redirect to HomeStack component
-const Tab = createBottomTabNavigator();
export default function Tabs() {
return (
<Tab.Navigator initialRouteName={homeName} >
<Tab.Screen name={ResultsName} component={ResultatenStack} />
<Tab.Screen name={homeName} component={HomeStack} />
<Tab.Screen name={settingsName} component={SignUpStack} />
</Tab.Navigator>
);
}
When using the same navigation method to direct to screens that are in the stack that I already am, it works fine. I hope someone can give me any pointers or help out! If you need any more info feel free to reach out!
PS: I'm very new to react-native so my apologies if I'm missing information.
I geas you are trying to navigate from stack navigator to tab navigator which is not ideal in react native you have to use nesting navigator
what I mean you have to use the tab navigator as a screen inside the stack navigator
this is React Navigation doc for nesting navigator https://reactnavigation.org/docs/nesting-navigators/

Force the screen defined in initialRouteName to be displayed when the tab button is pressed

I have a problem with bottom tab navigation. This is screen structure:
Main Tab:
Tab A
Screen A1
Tab B
Screen B1
Screen B2
I can navigate from Screen A1 to Screen B2 (changing tab).
I can navigate from Screen B1 to Screen B2.
This is the example code:
import React from "react";
import { StyleSheet, View, Text, Button } from "react-native";
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs";
const Tab = createBottomTabNavigator();
const Stack = createStackNavigator();
const TabAScreen1 = ({ route, navigation }) => {
return (
<View>
<Text>Tab A screen 1</Text>
<Button
title="Go to tab B screen 2"
onPress={() => {
navigation.navigate("TabBStack", { screen: "TabBScreen2" });
}}
/>
</View>
);
};
const TabBScreen1 = ({ route, navigation }) => {
return (
<View>
<Text>Tab B screen 1</Text>
<Button
title="Go to tab B screen 2"
onPress={() => {
navigation.navigate("TabBScreen2");
}}
/>
</View>
);
};
const TabBScreen2 = ({ route, navigation }) => {
return (
<View>
<Text>Tab B screen 2</Text>
</View>
);
};
function TabBStack() {
return (
<Stack.Navigator initialRouteName="TabBScreen1" screenOptions={{ headerShown: false }}>
<Stack.Screen name="TabBScreen1" component={TabBScreen1}/>
<Stack.Screen name="TabBScreen2" component={TabBScreen2}/>
</Stack.Navigator>
);
}
function MainTab() {
return (
<Tab.Navigator screenOptions={{ headerShown: false }}>
<Tab.Screen name="TabAScreen1" component={TabAScreen1}/>
<Tab.Screen name="TabBStack" component={TabBStack}/>
</Tab.Navigator>
);
};
const App = props => {
const navigationRef = useRef();
return (
<NavigationContainer>
<MainTab/>
</NavigationContainer>
);
};
const styles = StyleSheet.create({});
export default App;
Navigation packages:
"#react-navigation/bottom-tabs": "^6.2.0",
"#react-navigation/native": "^6.0.8",
"#react-navigation/stack": "^6.1.1",
At the beginning, if I navigate to Tab B using bottom tab button, Screen B1 is loaded. Then I can navigate to Screen B2 from Screen B1 or Screen A1. Being in Screen B2, if I tap on Tab B bottom tab button the Screen B2 is popped and Screen B1 is showed. This is the expected behavior.
The problem is this one. At the beginning, if I navigate to Screen B2 from Screen A1, Screen B2 is loaded. At this point, I can't navigate to screen B1 at all. If I tap on Tab B bottom tab button nothing happens, even initialRouteName of TabBStack is set to TabBScreen1. I think in this case the first screen in the stack is B2.
Is it possible to pop B2 (or all screens in the stack) and push B1 tapping bottom tab button? I know about listeners, but I don't know how to implement this behavior.
function MainTab() {
return (
<Tab.Navigator screenOptions={{ headerShown: false }}>
<Tab.Screen name="TabAScreen1" component={TabAScreen1}/>
<Tab.Screen name="TabBStack" component={TabBStack}
listeners={({ navigation }) => ({
tabPress: (e) => {
console.log("Tab B pressed");
// If current route is not Screen B1, then pop all and push Screen B1
},
})}
/>
</Tab.Navigator>
);
};
This only happens if you initially load the application start in stack A and have never been to stack B before. This causes the initial route of the TabBStack to not be mounted!
If you then navigate to a nested screen inside the stack of the TabBStack from TabAScreen1, the default route reset functionality does not work. The framework does only mount TabBScreen2 but not the initial route specified in that particular tab.
If we do the following instead:
Load the application: the default screen is TabAScreen1
Go to TabBStack using the bottom tab navigation.
Go back to TabAScreen1.
Click the Go to tab B screen 2 button
Press the TabBStack bottom tab button
You will notice that it now successfully resets the route. This is the default behavior used in most applications.
How do we solve this?
We have luck. The framework allows us to do this in a very convenient way by using the initial prop.
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.
In our case, this causes the TabBScreen1 to never be mounted. Thus, we can not reset to this route. If we provide initial: false while navigating to the nested screen, the navigation framework will not use TabBScreen2 as the initial route but TabBScreen1. If we do this, we can reset the route by pressing the TabBStack button again.
navigation.navigate("TabBStack", { screen: "TabBScreen2", initial: false });

How to use stack navigation in side drawer navigation with header in react navigation v6

i am using the React navigation version 6 and i want to header of navigation
with drawer and Stack
but when i use stack in drawer navigation then shows to two header
the below is code which i write
const StockStack = createNativeStackNavigator();
const StockScreen = ({ navigation }) => (
<StockStack.Navigator>
<StockStack.Screen name="StockList" component={StockList} />
<StockStack.Screen name="StockItemDetail" component={StockItemDetail}/>
</StockStack.Navigator>
)
and this the drawer navigation
return (
<Drawer.Navigator drawerContent={ props => <SideMenu {...props} /> }>
<Drawer.Screen name="StockScreenList" component={StockScreen} />
</Drawer.Navigator>
);
any can help you can i remove the drawer header

IOS Swipe Back gesture does not perfom navigation.goBack()

I have a drawer navigator with many child navigators.
On Android, both Header back arrow and navigation bar back button work and go back to previous screens.
E.g., if I navigate to a bScreen1 through the drawer, both buttons get me back to the Home Screen of the App i.e. aScreen1
On IOS, Header back arrow work fine, HOWEVER, swipe back gets me back to my login screen inside the AuthNavigator instead of aScreen1, which has 0 sens to me because it is outside the drawerNavigator, and at the same level inside the RootNavigator. The swipe back does not perform a navigation.goBack().
I have already tried overriding the swipe behavior by adding a listener on 'beforeRemove' event and then calling navigation.goBack(), but the wrong screen still shows up for a instant before moving to the right one (previous one)
...
import { createDrawerNavigator } from '#react-navigation/drawer'
import { createStackNavigator } from '#react-navigation/stack';
const DrawerNavigator = createDrawerNavigator();
const rootStack = createStackNavigator();
...
drawerNavigator() {
return (
<DrawerNavigator.Navigator>
<DrawerNavigator.Screen component={aNavigator} />
<DrawerNavigator.Screen component={bNavigator} />
...
<DrawerNavigator.Screen component={zNavigator} />
</DrawerNavigator.Navigator>
)}
aNavigator() {
return (
<ANavigator.Navigator>
<ANavigator.Screen component={aScreen1} />
...
<ANavigator.Screen component={aScreen10} />
</ANavigator.Navigator>
)}
bNavigator() {
return (
<ANavigator.Navigator>
<ANavigator.Screen component={bScreen1} />
...
<ANavigator.Screen component={bScreen10} />
</ANavigator.Navigator>
)}
<rootStack.Navigator initialRouteName="AuthNavigator" screenOptions={{ headerShown: false }}>
<rootStack.Screen name="AuthNavigator" component={createAuthNavigator} />
<rootStack.Screen name="DrawerNavigator" component={drawerNavigator} />
</rootStack.Navigator>
Ps: I am using all the latest versions of navigation packages
I had the same issue when I set animationEnabled: false, if you set it to true you should be able to swipe to switch screens.

React Navigation: How to trigger navigation.push() in bottom tab navigator?

Here is what I am trying to do in my app with react navigation:
There is a default bottom tab navigator.
The app will listen to changes in the data.
If there is a change in the data for any of the screens in the bottom tab navigator, trigger navigation.push() to refresh the component.
What I observed is that the default behavior of the bottom tab navigator is navigation.navigate()...i.e. unless I reload the app, the screens do not refresh themselves.
In short, how do I trigger navigation.push() in the tab navigator? e.g. in the sample code below, how do I set the navigation behavior?
Thanks a lot in advance!
//How do I trigger navigation.push() when each of the bottom tab is pressed?
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="Settings" component={SettingsStackScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
Pulled the following example from my code which solved the issue for me;
import { StackActions } from '#react-navigation/routers';
onPress={() => {
const pushAction =
StackActions.push('ProfileAnimal', { animal_id: item.id });
this.props.navigation.dispatch(pushAction);
this.props.navigation.navigate('ProfileAnimal', {animal_id: item.id});
};