Using drawer navigation and stack navigation at the same time - react-native

I am trying to nest a stack navigation inside a drawer navigation on snack expo. I asked this question before and was told to do it all over again. I did and still got errors. Initially I used a class, so I tried using a function instead . I would really appreciate if someone could explain what am I doing wrong? I can also post the link to my project if this helps https://snack.expo.io/#andreeam/it-in-the-valley
The error I get is
Device: (0:0) Cannot assign to read only property 'exports' of object '#<Object>'
Evaluating module://react-native-screens.js
Evaluating module://#react-navigation/drawer.js
Evaluating module://App.js.js
Loading module://App.js
Thank you
This is my code
import * as React from 'react';
import { createStackNavigator } from '#react-navigation/stack';
import { NavigationContainer } from '#react-navigation/native';
import { createDrawerNavigator } from '#react-navigation/drawer';
import SignIn from './components/SignIn';
import ForgotPassword from './components/ForgotPassword';
import Dashboard from './components/Dashboard';
import Advertisers from './components/advertisers';
import Adverts from './components/Adverts';
import Stats from './components/Stats';
import Plans from './components/Plans';
import About from './components/about';
import ManageAdvert from './components/ManageAdvert';
const Stack = createStackNavigator();
function Root () {
return (
<Stack.Navigator
initialRouteName="SignIn"
screenOptions={{
headerTitleAlign: 'center',
headerStyle: { backgroundColor: '#2d3436'},
headerTintColor: '#fff',
headerTitleStyle: { fontWeight: 'bold'}
}}>
<Stack.Screen
name="Reset your password"
component={ForgotPassword}
options={
{title: 'Reset your password'},
{headerLeft: null}
}
/>
<Stack.Screen
name="SignIn"
component={SignIn}
options = {
{headerShown: false,
title: 'SignOut'}
}
/>
<Stack.Screen
name="Dashboard"
component={Dashboard}
/>
<Stack.Screen
name="Advertisers"
component={Advertisers}
options={
{title: 'Advertisers'}
}
/>
<Stack.Screen
name="Adverts"
component={Adverts}
options={
{title: 'Adverts'}
}
/>
<Stack.Screen
name="Stats"
component={Stats}
options={
{title: 'Stats'}
}
/>
<Stack.Screen
name="Plans"
component={Plans}
options={
{title: 'Plans'}
}
/>
<Stack.Screen
name="Manage Adverts"
component={ManageAdvert}
options={
{title: 'Manage Adverts'}
}
/>
</Stack.Navigator>
);
}
const Drawer = createDrawerNavigator();
export default function App () {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="Root">
<Drawer.Screen name="Root" component={Root} />
<Drawer.Screen name="About" component={About} />
</Drawer.Navigator>
</NavigationContainer>
);
}

Fixed that, see snack here => https://snack.expo.io/#mustafaskir/ee857b
just updated packages in package.json, should fix that
here's what packages i updated, and i have to republish in my acc
"react-native-paper": "^3.10.1",
"react-native-screens": "^2.4.0",
"#react-navigation/stack": "^5.3.7",
"react-native-reanimated": "^1.8.0",
"#react-navigation/drawer": "^5.7.5",
"#react-navigation/native": "^5.4.0",
"react-native-safe-area-context": "^0.7.3",
"#react-native-community/masked-view": "^0.1.7"

Related

drawer navigation is giving error in react native

I added stack and bottom navigator in my app, and it is running correctly. But if I add drawer navigation then I am getting error
Below I have added my files
App.tsx:
import {NavigationContainer} from '#react-navigation/native';
import MainNavigator from '../src/navigator/MainNavigator';
import 'react-native-gesture-handler';
const App = () => {
return (
<NavigationContainer>
<MainNavigator />
</NavigationContainer>
);
};
MainNavigator.tsx:
import {createNativeStackNavigator} from '#react-navigation/native-stack';
import MyTabs from './TabNavigator';
const MainStack = createNativeStackNavigator();
const MainNavigator = () => {
return (
<MainStack.Navigator initialRouteName='StartupScreen'>
<MainStack.Screen
name='StartupScreen'
component={StartupScreen}
/>
<MainStack.Screen
name={'Main'}
component={MyTabs}
/>
</MainStack.Navigator>
);
};
TabNavigator.tsx: I have added drawer in this file
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import {createDrawerNavigator} from '#react-navigation/drawer';
const Drawer = createDrawerNavigator();
function DrawerNavigator() {
return (
<Drawer.Navigator>
<Drawer.Screen name="ReferScreen" component={ReferScreen} />
<Drawer.Screen name="OtherScreen" component={OtherScreen} />
</Drawer.Navigator>
);
}
const iconSize = 24;
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator initialRouteName="HomeScreen">
<Tab.Screen
name="HomeScreen"
component={HomeScreen}
options={{
headerTitle: '',
headerShown: false,
tabBarIcon: props =>
props.focused ? (
<ImageConfig.HomeIconOn height={iconSize} width={iconSize} />
) : (
<ImageConfig.HomeIconOff height={iconSize} width={iconSize} />
),
}}
/>
<Tab.Screen
name="ProfileScreen"
component={ProfileScreen}
options={{
tabBarIcon: props =>
props.focused ? (
<ImageConfig.SettingIconOn height={iconSize} width={iconSize} />
) : (
<ImageConfig.SettingIconOff height={iconSize} width={iconSize} />
),
}}
/>
<Tab.Screen name="drawer" component={DrawerNavigator} />
</Tab.Navigator>
);
}
and following are my dependencies in package.json:
"dependencies": {
"#react-navigation/bottom-tabs": "^6.5.5",
"#react-navigation/drawer": "^6.6.0",
"#react-navigation/native": "^6.1.3",
"#react-navigation/native-stack": "^6.9.9",
"react": "17.0.2",
"react-native": "0.68.5",
"react-native-gesture-handler": "^2.9.0",
"react-native-reanimated": "^2.14.4",
"react-native-safe-area-context": "^4.5.0",
"react-native-screens": "^3.19.0",
},
I am getting this error:
Invariant Violation: Module AppRegistry is not a registered callable module (calling runApplication). A frequent cause of the error
is that the application entry file path is incorrect.
This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.

Combining a stack navigator with a drawer navigator in react native

So I'm new to react native and react navigation.
I'm building an app that will have 7 main screens:
HomeScreen, ProfileScreen, CocktailDetailScreen and PublishRecipeScreen (which I want to be able to access through a drawer navigator).
LandingScreen, LoginScreen and RegisterScreen (which I don't want to show in the drawer navigator. I just want to show the LandingScreen when the user isn't logged in, and either of the other if the user want's to log in or register).
I've been able to put up a stack navigator that works fine, but I don't understand how to combine this with the drawer navigator I want. I've tried different approaches but I get errors like:
The action 'OPEN_DRAWER' was not handled by any navigator.
Is your screen inside a Drawer navigator?
or
Uncaught Error: Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app, so this was probably an error. If this was intentional, pass 'independent={true}' explicitly. Note that this will make the child navigators disconnected from the parent and you won't be able to navigate between them.
This is my code so far.
App.tsx
import { SafeAreaProvider } from 'react-native-safe-area-context'
import useCachedResources from './hooks/useCachedResources'
import Navigation from './navigation'
export default function App() {
const isLoadingComplete = useCachedResources()
if (!isLoadingComplete) {
return null
} else {
return (
<SafeAreaProvider>
<Navigation />
</SafeAreaProvider>
)
}
}
(navigation) index.tsx
import { NavigationContainer } from '#react-navigation/native'
import { createNativeStackNavigator } from '#react-navigation/native-stack'
import * as React from 'react'
import LandingScreen from '../screens/LandingScreen'
import LoginScreen from '../screens/LoginScreen'
import RegisterScreen from '../screens/RegisterScreen'
import HomeScreen from '../screens/HomeScreen'
import ProfileScreen from '../screens/ProfileScreen'
import CocktailDetailScreen from '../screens/CocktailDetailScreen'
import PublishRecipeScreen from '../screens/PublishRecipeScreen'
import Header from '../components/Header'
import DrawerNavigator from '../components/DrawerNavigator'
import { RootStackParamList } from '../types'
export default function Navigation() {
const Stack = createNativeStackNavigator<RootStackParamList>()
return (
<NavigationContainer>
<Stack.Navigator >
<Stack.Screen name='LandingScreen' component={LandingScreen} options={{headerShown: false}} />
<Stack.Screen name='LoginScreen' component={LoginScreen} options={{headerShown: false}} />
<Stack.Screen name='RegisterScreen' component={RegisterScreen} options={{headerShown: false}} />
<Stack.Screen name='HomeScreen' component={HomeScreen} options={{ header: () => <Header/> }} />
<Stack.Screen name='ProfileScreen' component={ProfileScreen} options={{ header: () => <Header/> }} />
<Stack.Screen name='CocktailDetailScreen' component={CocktailDetailScreen} options={{ header: () => <Header/> }} />
<Stack.Screen name='PublishRecipeScreen' component={PublishRecipeScreen} options={{ header: () => <Header/> }} />
</Stack.Navigator>
</NavigationContainer>
)
}
header.tsx
import React from 'react'
import { useNavigation } from '#react-navigation/native'
import { useDrawerStatus } from '#react-navigation/drawer'
import { DrawerActions } from '#react-navigation/native'
import { StyleSheet, Text, View } from 'react-native'
import { AntDesign } from '#expo/vector-icons'
const Header = () => {
const navigation = useNavigation()
return (
<View style={styles.container}>
<Text style={styles.title} onPress={() => navigation.navigate('RegisterScreen')}>Mixr</Text>
<View style={styles.iconContainer} >
<AntDesign name='user' style={styles.icon} size={30} color='white' onPress={() => navigation.dispatch(DrawerActions.openDrawer())} />
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
backgroundColor: '#E51C27',
alignSelf: 'stretch'
},
title: {
fontSize: 40,
fontWeight: 'bold',
marginTop: 6,
marginBottom: 6,
marginLeft: 10
},
iconContainer: {
backgroundColor: 'black',
borderBottomLeftRadius: 50,
borderBottomRightRadius: 50,
borderTopLeftRadius: 50,
borderTopRightRadius: 50,
marginRight: 10
},
icon: {
padding: 5
}
})
export default Header
DrawerNavigator.tsx
import React from 'react'
import { createDrawerNavigator, useDrawerStatus } from '#react-navigation/drawer'
import { NavigationContainer } from '#react-navigation/native'
import HomeScreen from '../screens/HomeScreen'
import ProfileScreen from '../screens/ProfileScreen'
import CocktailDetailScreen from '../screens/CocktailDetailScreen'
import PublishRecipeScreen from '../screens/PublishRecipeScreen'
const DrawerNavigator = () => {
const Drawer = createDrawerNavigator()
return (
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name='HomeScreen' component={HomeScreen} />
<Drawer.Screen name='ProfileScreen' component={ProfileScreen} />
<Drawer.Screen name='CocktailDetailScreen' component={CocktailDetailScreen} />
<Drawer.Screen name='PublishRecipeScreen' component={PublishRecipeScreen} />
</Drawer.Navigator>
</NavigationContainer>
)
}
export default DrawerNavigator
I want to show a header in all of this pages (HomeScreen, ProfileScreen, CocktailDetailScreen and PublishRecipeScreen) and from that header be able to open/close the drawer. I don't quite understand how to link the stack navigator with the drawer.
From a more theoretical point of view, I don't really understand the difference between the stack navigator, the drawer, and other options like tab or bottom navigators.
I mean, besides that the drawer navigator shows in a drawer and the bottom one shows at the bottom. Is there a conceptual difference between them?
Full code can be found here: https://github.com/coccagerman/mixr
I think I figured it out.
What I did is nest the drawer navigator within the stack navigator.
To do so, I passed the Drawer navigator as the component of each of the screens I wanted it to be in.
Like so:
(navigation) index.tsx
import { NavigationContainer } from '#react-navigation/native'
import { createNativeStackNavigator } from '#react-navigation/native-stack'
import * as React from 'react'
import LandingScreen from '../screens/LandingScreen'
import LoginScreen from '../screens/LoginScreen'
import RegisterScreen from '../screens/RegisterScreen'
import Header from '../components/Header'
import DrawerNavigator from '../components/DrawerNavigator'
import { RootStackParamList } from '../types'
export default function Navigation() {
const Stack = createNativeStackNavigator<RootStackParamList>()
return (
<NavigationContainer>
<Stack.Navigator >
<Stack.Screen name='LandingScreen' component={LandingScreen} options={{headerShown: false}} />
<Stack.Screen name='LoginScreen' component={LoginScreen} options={{headerShown: false}} />
<Stack.Screen name='RegisterScreen' component={RegisterScreen} options={{headerShown: false}} />
<Stack.Screen name='HomeScreen' component={DrawerNavigator} options={{ header: () => <Header/> }} />
<Stack.Screen name='ProfileScreen' component={DrawerNavigator} options={{ header: () => <Header/> }} />
<Stack.Screen name='CocktailDetailScreen' component={DrawerNavigator} options={{ header: () => <Header/> }} />
<Stack.Screen name='PublishRecipeScreen' component={DrawerNavigator} options={{ header: () => <Header/> }} />
</Stack.Navigator>
</NavigationContainer>
)
}
And in the drawer navigator I assign the corresponding screen component to each screen:
DrawerNavigator.tsx
import React from 'react'
import { createDrawerNavigator } from '#react-navigation/drawer'
import HomeScreen from '../screens/HomeScreen'
import ProfileScreen from '../screens/ProfileScreen'
import CocktailDetailScreen from '../screens/CocktailDetailScreen'
import PublishRecipeScreen from '../screens/PublishRecipeScreen'
const DrawerNavigator = () => {
const Drawer = createDrawerNavigator()
return (
<Drawer.Navigator>
<Drawer.Screen name='Home' component={HomeScreen} options={{headerShown: false}} />
<Drawer.Screen name='Profile' component={ProfileScreen} options={{headerShown: false}} />
<Drawer.Screen name='CocktailDetail' component={CocktailDetailScreen} options={{headerShown: false}} />
<Drawer.Screen name='PublishRecipe' component={PublishRecipeScreen} options={{headerShown: false}} />
</Drawer.Navigator>
)
}
export default DrawerNavigator
I still find this a bit confusing though, and I guess there's probably a simpler way to write this.
Useful resources I've found on this topic:
https://reactnavigation.org/docs/nesting-navigators/
https://blog.waldo.io/combining-navigators-in-react-navigation/

React native drawer navigation with I18nManager.forceRTL isn't working

Been trying to implement #react-navigation/drawer with #react-navigation/native-stack and forcing the app to be RTL, using Expo.
App.tsx:
import { I18nManager } from 'react-native'
import { SafeAreaProvider } from 'react-native-safe-area-view'
import {useLoading} from '#hooks'
I18nManager.forceRTL(true)
I18nManager.allowRTL(true)
export default function App() {
const isLoadingComplete = useLoading()
if (!isLoadingComplete) {
return null
} else {
return (
<SafeAreaProvider style={{flex:1}}>
<Navigation />
<StatusBar style="dark" />
</SafeAreaProvider>
)
}
}
Navigation.tsx:
import { createNativeStackNavigator, NativeStackNavigationOptions } from '#react-navigation/native-stack'
import { createDrawerNavigator } from '#react-navigation/drawer'
import { NavigationContainer } from '#react-navigation/native'
const Stack = createNativeStackNavigator<RootStackParamList>()
const Drawer = createDrawerNavigator<RootDrawerParamList>()
function RootNavigator() {
return (
<Stack.Navigator screenOptions={{presentation: 'modal', headerShown: false}}>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Root" component={DrawerNavigator} />
<Stack.Screen name="Customer" component={CustomerScreen} />
</Stack.Navigator>
)
}
function DrawerNavigator() {
return (
<View style={styles.container}>
<Drawer.Navigator initialRouteName='Customers' screenOptions={{headerRight: Logout}}>
<Drawer.Screen name="Home" component={HomeScreen} options={{title: Lang.Navigation.Home}} />
<Drawer.Screen name="Customers" component={CustomersScreen} options={{title: Lang.Navigation.Customers}} />
</Drawer.Navigator>
</View>
)
}
export default function Navigation() {
return (
<NavigationContainer ref={navigationRef} linking={LinkingConfiguration}>
<RootNavigator />
</NavigationContainer>
)
}
Dependencies:
"#react-navigation/drawer": "^6.1.8",
"#react-navigation/native": "^6.0.6",
"#react-navigation/native-stack": "^6.2.5",
"expo": "~44.0.0",
"react": "17.0.1",
"react-native": "0.64.3",
"react-native-safe-area-view": "^1.1.1",
The result i'm getting when clicking on the menu built-in hamburger is that the screen does become grayish but the menu never pops in. Using inspect I found that there is a problem with the menu's "left" and "translateX" settings automatically given by the react navigation plugin.
Everything works well when removing the 'ForceRTL' part, but I need the app the be RTL.
instead of using the following code.
I18nManager.forceRTL(true)
I18nManager.allowRTL(true)
fix for this issue is to use direction:'rtl' in the style of Root level component. sample working code demo https://snack.expo.dev/PIIGNx70v
sample code
import * as React from 'react';
import { Button, View } from 'react-native';
import { createDrawerNavigator } from '#react-navigation/drawer';
import { NavigationContainer } from '#react-navigation/native';
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button onPress={navigation.openDrawer} title="Open drawer" />
</View>
);
}
const Drawer = createDrawerNavigator();
export default function App() {
return (
<View style={{ flex: 1, direction: 'rtl' }}>
<NavigationContainer>
<Drawer.Navigator drawerPosition="right" initialRouteName="Home">
<Drawer.Screen name="Home" component={HomeScreen} />
</Drawer.Navigator>
</NavigationContainer>
</View>
);
}

Nesting stack navigation inside a drawer navigation

I am trying to nest a stack navigation inside a drawer navigation on snack expo. I asked this question before and was told to do it all over again. I did and I still get different errors. I would really appreciated if someone could explain what am I doing wrong? I can also post the link to my project if this helps https://snack.expo.io/#andreeam/it-in-the-valley
Thank you
Errors below:
Device: (3:9741) (0,l.useLinkBuilder) is not a function. (In '(0,l.useLinkBuilder)()', '(0,l.useLinkBuilder)' is undefined)
And I also get
Device: (104:51757) r.render is not a function. (In 'r.render()', 'r.render' is undefined)
Cannot assign to read only property 'exports' of object '#<Object>'
Evaluating module://react-native-screens.js
Evaluating module://#react-navigation/drawer.js
Evaluating module://App.js.js
Loading module://App.js
Here is my app.js
import * as React from 'react';
import { createStackNavigator } from '#react-navigation/stack';
import { NavigationContainer } from '#react-navigation/native';
import SignIn from './components/SignIn';
import ForgotPassword from './components/ForgotPassword';
import Dashboard from './components/Dashboard';
import Advertisers from './components/Advertisers';
import Adverts from './components/Adverts';
import Stats from './components/Stats';
import Plans from './components/Plans';
import ManageAdverts from './components/manageadvert';
const Stack = createStackNavigator();
class MyStack extends React.Component {
render() {
return (
<Stack.Navigator
initialRouteName="SignIn"
screenOptions={{
headerTitleAlign: 'center',
headerStyle: { backgroundColor: '#2d3436'},
headerTintColor: '#fff',
headerTitleStyle: { fontWeight: 'bold'}
}}>
<Stack.Screen
name="Reset your password"
component={ForgotPassword}
options={
{title: 'Reset your password'},
{headerLeft: null}
}
/>
<Stack.Screen
name="SignIn"
component={SignIn}
options = {
{headerShown: false,
title: 'SignOut'}
}
/>
<Stack.Screen
name="Dashboard"
component={Dashboard}
/>
<Stack.Screen
name="Advertisers"
component={Advertisers}
options={
{title: 'Advertisers'}
}
/>
<Stack.Screen
name="Adverts"
component={Adverts}
options={
{title: 'Adverts'}
}
/>
<Stack.Screen
name="Stats"
component={Stats}
options={
{title: 'Stats'}
}
/>
<Stack.Screen
name="Plans"
component={Plans}
options={
{title: 'Plans'}
}
/>
<Stack.Screen
name="Manage Adverts"
component={ManageAdverts}
options={
{title: 'Manage Adverts'}
}
/>
</Stack.Navigator>
);
}}
export default class App extends React.Component {
render() {
return (
<NavigationContainer>
<MyStack />
</NavigationContainer>
);
}
}
I got this error when I upgraded expo to version 37. I was able to resolve this issue by updating the relevant reactmodules to the latest version.

To attain drawer navigation menu on the right in react native

When i am adding selected code then its showing undefined object (evaluating 'route.routeName').
Navigation drawer is by default on the left. How to attain it on right side ?
import React, { Component } from "react";
import { Platform, StyleSheet, Text, View } from "react-native";
import { DrawerNavigator } from "react-navigation";
import ScreenFirst from "./src/ScreenFirst";
import ScreenTwo from "./src/ScreenTwo";
const DrawerExample = DrawerNavigator(
{
ScreenFirst: { screen: ScreenFirst },
ScreenTwo: { screen: ScreenTwo }
},
{
drawerPosition: "right",
drawerWidth: 100
}
);
export default DrawerExample;
if you are using navigation 3.x you will need to import these guys
import {createDrawerNavigator, createAppContainer} from 'react-navigation'
then try this one:
const DrawerExample = DrawerNavigator(
{
ScreenFirst: { screen: ScreenFirst },
ScreenTwo: { screen: ScreenTwo }
},
{
drawerPosition: "right",
drawerWidth: 100
}
);
const MyApp = createAppContainer(DrawerExample);
export default MyApp
For who comes from React Navigation V5. Just call drawerPosition like below:
<Drawer.Navigator initialRouteName="SignIn" drawerPosition="right">
<Drawer.Screen name="welcome" component={Welcome} />
</Drawer.Navigator>
import {DrawerActions} from '#react-navigation/native';
<Drawer.Navigator screenOptions={{ drawerPosition: 'right', }}> <Drawer.Screen name="Home" component={Home} options={{ headerStyle: { backgroundColor: 'orange', }, headerTintColor: 'black', headerLeft:false, headerRight: () => ( <TouchableOpacity onPress={() => navigation.dispatch(DrawerActions.openDrawer())}> ), }} /> <Drawer.Screen name="Standings" component={Standings} /> </Drawer.Navigator>
it worked for me
For 6.x
<NavigationContainer>
<Drawer.Navigator initialRouteName="Home" screenOptions={{drawerPosition:"right"}}
>
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Notifications" component={NotificationsScreen} />
</Drawer.Navigator>
</NavigationContainer>
In React Navigation version 5, add the drawerPosition prop with value right in your Drawer Navigator.
<Drawer.Navigator drawerPosition="right">
<Drawer.Screen name="Feed" component={Feed} />
<Drawer.Screen name="Article" component={Article} />
</Drawer.Navigator>
Read here for the official docs.