React Navigation - Drawer inside Stack go back - react-native

Taking this example for the official documentation :
function Root() {
return (
<Drawer.Navigator>
<Drawer.Screen name="Home" component={Home} />
<Drawer.Screen name="Profile" component={Profile} />
<Stack.Screen name="Settings" component={Settings} />
</Drawer.Navigator>
);
}
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Root"
component={Root}
options={{ headerShown: false }}
/>
<Stack.Screen name="Feed" component={Feed} />
</Stack.Navigator>
</NavigationContainer>
);
}
They just explain here how to navigate to the Profile screen from the Feed screen like this :
navigation.navigate('Root', { screen: 'Profile' });
I would to know how can I navigate to the Feed screen from the Profile screen;

You can just use the navigation object and its navigate function since the Feed screen is nested inside the same navigator as the Root stack.
Destructure the navigation object from the props of Profile.
function Profile({navigation}) {
return ...
}
Now, just use the navigation object as follows in order to navigate to Feed.
navigation.navigate("Feed")

Related

How do I nest my tab navigator with my stack navigator in react native?

Good evening,
I successfully created a project inside react native now I would like to nest my tab navigator with my stack navigator. I'm getting errors when I put my tab navigator with the stack navigator. My tab navigation code is:
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Earnings" component={EarningsScreen} />
</Tab.Navigator>
);
}
function Root() {
return (
<NavigationContainer>
<MyTabs/>
</NavigationContainer>
);
My stack navigator code is:
function MyStack() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Notifications" component={NotificationsScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<MyStack />
</NavigationContainer>
);
}
It looks like you're using two separate NavigationContainers, and you're not nesting the navigators at all; the code for each is completely separate.
Given that your question is about needing the tabs within the stack, try this instead:
delete the Root component (you should only have one NavigationContainer in your app)
use the MyTabs component as one of your stack screens
Example:
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Earnings" component={EarningsScreen} />
</Tab.Navigator>
);
}
function MyStack() {
return (
<Stack.Navigator>
{/* Tabs are inserted here */}
<Stack.Screen name="Tabs" component={MyTabs} />
<Stack.Screen name="Notifications" component={NotificationsScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<MyStack />
</NavigationContainer>
);
}

Navigate to Screen which are not inside BottomTabNavigator React Native

I have developed a bottomTabNavigator in react-native and I have 3 main routes which I want to show in my bottomtabnavigator which are 1) Home, 2) Profile, 3) Chat, So I wrote the following code:
const Stack = createNativeStackNavigator();
const Tab = createBottomTabNavigator();
const Navigation = () => {
return (
<>
<Tab.Navigator>
{user.authLoadingState ? (
<Tab.Screen name="Home" component={LoadingScreen} />
) : user.isLoggedIn ? (
<>
<Tab.Screen
name="Home"
component={HomeScreen}
/>
<Tab.Screen
name="Profile"
component={ProfileScreen}
/>
<Tab.Screen
name="Chat"
component={ChatScreen}
/>
<Stack.Screen name="Update" component={UpdateScreen} /> // this is the screen I don't want in my bottomTab but I want to navigate to it using useNavigation hook.
</>
) : (
<>
<Stack.Screen name="First" component={FirstScreen} />
<Stack.Screen name="SignIn" component={SignInScreen} />
<Stack.Screen name="SignUp" component={RegisterScreen} />
</>
)}
</Tab.Navigator>
</>
);
};
Now, when I go to my Profile screen, I have a button which (should) navigate to another screen which is not mentioned in my Tab Navigator definition, how can I navigate to that screen because obviously I do not want to fill my bottomTabNavigator with different screens, I only want to keep the main screens in my bottomTabNavigator not all. When I was using Stack.Navigator alone, it was fine because I could just keep all my screens under <Stack.Navigator></Stack.Navigator> and navigate to any screen using navigator.navigate(nameOfScreen) with const navigator = useNavigation(). But now, if a screen which is not mentioned inside Tab.Navigator will throw an error if I navigate saying Screen does not exists. Is there any thing I could do to make it work?
to navigate between tab and stack screen you can do this way :
const Tab = createBottomTabNavigator();
const Stack = createStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen
name="Home"
component={HomeScreen}
/>
<Tab.Screen name="Profile Screen" component={StackScreens} />
<Tab.Screen
name="Chat"
component={ChatScreen}
/>
</Tab.Navigator>
</NavigationContainer>
)
function StackScreens() {
return (
<Stack.Navigator screenOptions={{ headerShown: false }} >
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Update" component={UpdateScreen} /> // this is the screen I don't want in my bottomTab but I want to navigate to it using useNavigation hook.
</Stack.Navigator>
);
}
}
I'm not sure if it is exactly that you want, but you can now access from "Profile" to the "UpdateScreen" without showing it in the bottomTabNavigator

react native navigation between screens

I'm trying to use reactnavigation.org library and I have some issue with that. I have two types of navigation screens. Two screens are a registration and authorization. And others are regular app screens. Problem is that I can't render parent component App.js or other functionality to reload app from child component and thus change my screens block. Navigation between screens Run, History, Profile, OtherRunners works fine. Navigation between screens Main and Enter works fine. But if I need navigate from Run to Main, or from Enter to Run there is a problem.
App.js
const App = () => {
const Stack = createStackNavigator()
const Drawer = createDrawerNavigator()
const [loggedIn, setLoggedIn] = useState(false)
async function getUserEmail(){
if(await AsyncStorage.getItem('#email')){
setLoggedIn(true)
}else{
setLoggedIn(false)
}
}
getUserEmail()
function MenuDraw(){
return(
<Drawer.Navigator
drawerContentOptions={}
drawerType={}
drawerStyle={{}}
>
<Drawer.Screen
name="Run"
component={Run}
options={}
/>
<Drawer.Screen
name="History"
component={History}
options={}
/>
<Drawer.Screen
name="Profile"
component={Profile}
options={}
/>
<Drawer.Screen
name="OtherRunners"
component={OtherRunners}
options={}
/>
<Drawer.Screen
name="LogOut"
component={Run}
initialParams={{action: 'logout'}}
options={}
/>
</Drawer.Navigator>
)
}
function MyDrawer(){
if(loggedIn){
return(
<Stack.Navigator
screenOptions={{headerShown: false}}
initialRouteName={"MenuDraw"}
>
<Stack.Screen name="MenuDraw" component={MenuDraw}/>
<Stack.Screen name="Details" component={Details}/>
</Stack.Navigator>
)
}else{
return (
<Stack.Navigator
screenOptions={{headerShown: false}}
initialRouteName={"Main"}
>
<Stack.Screen name="MenuDraw" component={MenuDraw} />
<Stack.Screen name="Details" component={Details} />
<Stack.Screen name="Main" component={Main} />
<Stack.Screen name="Enter" component={Enter} />
</Stack.Navigator>
)
}
}
return(
<NavigationContainer>
<MyDrawer/>
</NavigationContainer>
)
}
export default App;
I tried using reload app tools, but those wasn't help me. They are wasn't working. In this section of code which is below. On the Run screen.
Run.js
const Run = ({navigation,route}) => {
const clearStorage = async () => {
await AsyncStorage.clear()
}
if(route.params){
if(route.params.action === 'logout'){
clearStorage()
navigation.navigate("Main", {})
}
}
}
export default Run;
I'm trying to logout by cleaning the storage and navigate to Main screen. But it's not working on release mode. I've tried this, which is below.
App.js
function MyDrawer(){
if(loggedIn){
return(
<Stack.Navigator
screenOptions={{headerShown: false}}
initialRouteName={"MenuDraw"}
>
<Stack.Screen name="MenuDraw" component={MenuDraw}/>
<Stack.Screen name="Details" component={Details}/>
++++ <Stack.Screen name="Main" component={Main} />
++++ <Stack.Screen name="Enter" component={Enter} />
</Stack.Navigator>
)
}else{
return (
<Stack.Navigator
screenOptions={{headerShown: false}}
initialRouteName={"Main"}
>
<Stack.Screen name="MenuDraw" component={MenuDraw} />
<Stack.Screen name="Details" component={Details} />
<Stack.Screen name="Main" component={Main} />
<Stack.Screen name="Enter" component={Enter} />
</Stack.Navigator>
)
}
}
Not working either way. How can I fix it? Can I render App.js component from child screens? Or perhaps I should create two screen blocks line
<Stack.Screen name="MenuDraw" component={MenuDraw}/>
<Stack.Screen name="MenuRegister" component={MenuRegister}/>
and put all my screens by belongings to match section?
I need to logout from this section:
App.js
some code
<Drawer.Screen
name="LogOut"
component={Run}
initialParams={{action: 'logout'}}
options={}
/>
</Drawer.Navigator>
some code
Did you try using useEffect hook, to get on the road? :-)
useEffect(() => {
const getUserEmail = async () => {
if(await AsyncStorage.getItem('#email')){
setLoggedIn(true)
}else{
setLoggedIn(false)
}
};
getUserEmail();
}, []);

React Native: Different headers for different screens in Stack Navigator

I am using #react-navigation/stack version ^5.5.1. I am trying to have different headers on different screens in my Stack Navigation. For example, on Master, I want no header, i.e., headerMode="none"; on Home, I want a custom header, and on Details I want a different custom header. How do I achieve this? This is my current code:
const AppStack = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Master" component={ Master } />
<Stack.Screen name="Home" component={ Home } />
<Stack.Screen name="Details" component={ Details } />
</Stack.Navigator>
</NavigationContainer>
)
}
I just figured it out.
First, put headerMode="screen" on the Stack.Navigator. This moves control of the header to each screen. Then use the syntax as shown below for each individual screen.
const AppStack = () => {
return (
<NavigationContainer>
<Stack.Navigator headerMode="screen">
<Stack.Screen name="Master" component={ Master } options={{ headerShown: false }} />
<Stack.Screen name="Home" component={ Home } options={{ headerTitle: props => <MyCustomHeader {...props} /> }}/>
<Stack.Screen name="Details" component={ Details } options={{ headerTitle: props => <MyOtherCustomHeader {...props} /> }}/>
</Stack.Navigator>
</NavigationContainer>
)
}

How to pass params to Stack from an other Stack React Native?

My problem is that I have a Profile Stack that contains all the screens that you can reach from your / user's profile. I put this Stack to my DrawerStack and also to my HomeScreen Stack because these are the two possible ways to navigate there. But when I navigate there with some params it says that the route's params are undefined.
Profile Stack
function ProfileNavigator() {
return (
<Stack.Navigator>
<Stack.Screen name="ProfileScreen" component={Profile} />
...Other Screens
</Stack.Navigator>
);
}
Home Navigator
function HomeNavigator() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" options={{headerShown: false}} component={Home} />
<Stack.Screen name="Profile" options={{headerShown: false}} component={ProfileNavigator}/>
... Other Screens
</Stack.Navigator>
);
}
Drawer Navigator
<NavigationContainer>
<Drawer.Navigator
drawerContent={props => <CustomDrawerNavigator {...props} />}
initialRouteName="Home">
<Drawer.Screen name="Home" component={BottomNavigator} />
<Drawer.Screen
name="Profile"
options={{headerShown: false}}
component={ProfileNavigator}
/>
</Drawer.Navigator>
</NavigationContainer>
Navigate to the Profile
onPress={() => props.navigation.navigate('Profile', {current_user: true})}
I can pass Params and Navigate to the Profile If I don't use Stack but then I have to add every Profile Screens to every other Stack and I don't think is it efficient. I read somewhere that the similar names can cause such a problem but I just couldn't wrap my head around the problem.
So finally I found the answer in the docs.
I had to navigate like this:
props.navigation.navigate('Profile', {
screen: 'Profile',
params: { current_user: true },
});
And I also changed the ProfileScreen name to Profile in the ProfileNavigator.