I`m developing an APP for a championship and I have a HomeScreen where the Manager should LOGIN so he/she can update the results.
My problems is: I have a Drawer Navigator and a static password.
How can I get the prop isAdmin to the other screens??
Situation Example:
Screen named 'Points' has a Text Input which enabled status will depend on a function that evaluates if isAdmin= true.
HomeScreen:
export default function Login(){
const [senha, setSenha] = useState('');
var isAdmin = false;
function passCheck(pass){
if(pass == 'Adminlaje'){
isAdmin=true;
alert('Signed In !')
}
else
alert('Wrong password !');
}
return(
<SafeAreaView>
<TextInput
value = {senha}
onChangeText = { (senha) => setSenha(senha) }
/>
<TouchableOpacity onPress = {() => passCheck(senha)}>
<Text>Entrar</Text>
</TouchableOpacity>
</SafeAreaView>
);
}
My Drawer:
const Screens = ({navigation}) =>{
return(
<Stack.Navigator>
<Stack.Screen name = 'HomeScreen' component ={Login}
options={{
headerLeft: () =>(
<TouchableOpacity style = {styles.button} onPress = {()=> navigation.toggleDrawer()}>
<Entypo name="menu" size={35} color="black" />
</TouchableOpacity>
)
}}>
</Stack.Screen>
<Stack.Screen name = 'Points' component ={Points}
options={{
headerLeft: () => (
<TouchableOpacity style = {styles.button} onPress = {()=> navigation.toggleDrawer()}>
<Entypo name="menu" size={35} color="black" />
</TouchableOpacity>
),
}}
>
</Stack.Screen>
</Stack.Navigator>
);
};
const DrawerContent = (props) => {
return(
<DrawerContentScrollView {...props}>
<SafeAreaView>
<DrawerItem
label='HomeScreen'
onPress = {() => props.navigation.navigate('Login')}
/>
<DrawerItem
label='Points'
onPress = {() => props.navigation.navigate('Points')}
/>
</SafeAreaView>
</DrawerContentScrollView>
)
}
export default () => {
return(
<Drawer.Navigator
initialRouteName = 'Login'
drawerContent={props => <DrawerContent {...props}/>}
>
<Drawer.Screen name = 'Screens' component ={Screens}/>
</Drawer.Navigator>
);
};
The answer might depend on what versions of react-navigation and react-navigation-drawer you are using. On a project using "react-navigation": "^4.0.10", and "react-navigation-drawer": "^2.3.3" this is what works for me:
.............
import { NavigationEvents, NavigationActions } from 'react-navigation';
export default class HomeScreen extends Component {
..........
constructor(props){
super(props)
this.state = {language: 'English', menuOpen: false};
}
...................
render(){
const { navigation } = this.props;
const setParamsAction = NavigationActions.setParams({
params: { isAdmin: this.state.isAdmin },
key: 'PointsScreen',
});
const setParamsTwo = NavigationActions.setParams({
params: { isAdmin: this.state.isAdmin },
key: 'OtherScreen',
});
return(
<View style={styles.container}>
<NavigationEvents
onDidBlur={payload => {this.setState({menuOpen: true})}}
onWillFocus={payload => {this.setState({menuOpen: false});
this.backHandler = BackHandler.addEventListener('hardwareBackPress', () =>
{
this.props.navigation.dispatch(setParamsAction);
this.props.navigation.dispatch(setParamsTwo);
this.props.navigation.navigate('PointsScreen');
return true;
})}}
/>
In this example I'm sending the info to other screens when I hit backhandler, but it works the same way for any other navigation event. So for example if you want to add this to your drawer open button you would just substitute this.props.navigation.openDrawer(); for this.props.navigation.navigate('PointsScreen');.
In other screens I have:
.............
render(){
const { navigation } = this.props;
const isAdmin = navigation.getParam('isAdmin') || '';
In the drawer screen I have:
render(){
const { navigation } = this.props;
const pointsProps = navigation.getChildNavigation('PointsScreen');
const isAdmin = pointsProps.getParam('isAdmin') || "";
Related
this is the scenario:
In Home Route, there is a dropdown which contains SubSystems and based on each subSystem menu items are different. So, when I change subSystem, Menu Items of drawer should update.
I have implemented my drawer to get dynamic items like below code. But, the problem is that when then SubSystems are loaded I go to get the menu items after that I update the menuData state the whole component recompiles and it falls into a loop.
How Can I Overcome This Problem ?
MY CODE
StackNavigationManager.js
import {AuthContext} from './context';
const StackNavigationManager = () => {
const [menuData, setMenuData] = React.useState([]);
const authContext = React.useMemo(() => ({
validateMenuData: menuData => {
setMenuData(menuData);
},
}));
const DrawerScreen = ({route, navigation}) => (
<Drawer.Navigator
drawerContent={props => <CustomDrawerContent {...props} />}>
<Drawer.Screen
name="HomeDrawer"
component={Home} />
</Drawer.Navigator>
);
function CustomDrawerContent(props) {
return (
<SafeAreaView style={{flex: 1}}>
<DrawerItemList {...props} />
<FlatList
data={menuData}
keyExtractor={data => data.id.toString()}
renderItem={({item}) => {
return (
<DrawerItem
label={item.name}
onPress={() => alert(item.id)}></DrawerItem>
);
}}
/>
</SafeAreaView>
);
}
return (<AuthContext.Provider value={authContext}>
<NavigationContainer>
<Stack.Navigator
initialRouteName={initialRoute}>
<Stack.Screen
name="Home"
component={DrawerScreen}
options={{
headerShown: false,
}}
/>
</Stack.Navigator>
</NavigationContainer>
</AuthContext.Provider>);
Context.js
import React from 'react';
export const AuthContext = React.createContext();
Home.js
import {AuthContext} from './context';
const home = ({navigation}) => {
const {validateMenuData} = React.useContext(AuthContext);
React.useEffect(() => {
console.log('MOUNTED EFFECT');
getSubSystems();
return () => {
isMounted = false;
console.log('UNMOUNTED EFFECT');
};
}, []);
const getSubSystems = async () => {
const subSystemModel = {
isActive: true,
isVisible: true,
};
fetchSubSystemData(
subSystemModel,
response => {
if (response.list !== null) {
let listData = [...response.list];
fetchMenuAction(
listData[0].id,
response2 => {
validateMenuData([...response2.list]);
},
);
}
},
() => {},
);
};
I just started to learn React-native. In this app I have a two buttons in header, first 'Todo', second 'Tags'. I want to chang content by press on these buttons. I think I need to change state.for clarityWhat I mean, when i tap on the button Tags, below I get TagScreen component, exactly the same for the button Todo. How to connect these components so that they work correctly?
app.js
import React, { useState } from 'react'
import { StyleSheet, View, FlatList } from 'react-native'
import { Navbar } from './src/Navbar'
import { TagScreen } from './src/screens/TagScreen'
import { TodoScreen } from './src/screens/TodoScreen'
export default function App() {
const [todos, setTodos] = useState([])
const [tags, setTags] = useState([])
const [appId, setAppId] = useState([])
const addTodo = title => {
setTodos(prev => [
...prev,
{
id: Date.now().toString(),
title
}
])
}
const addTags = title => {
setTags(prev => [
...prev,
{
id: Date.now().toString(),
title
}
])
}
const removeTags = id => {
setTags(prev => prev.filter(tag => tag.id !== id))
}
const removeTodo = id => {
setTodos(prev => prev.filter(todo => todo.id !== id))
}
return (
<View>
<Navbar title='Todo App!' />
<View style={styles.container}>
<TagScreen addTags={addTags} tags={tags} removeTags={removeTags}/>
{/* <TodoScreen todos={todos} addTodo={addTodo} removeTodo={removeTodo} /> */}
{/* HERE MUST CHANGED COMPONENTS */}
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
paddingHorizontal: 30,
paddingVertical: 20
}
})
navbar.js
import React from 'react'
import { View, Text, StyleSheet, Button, TouchableOpacity } from 'react-native'
export const Navbar = ({ title }) => {
return (
<View style={styles.padding}>
<View style={styles.navbar}>
<TouchableOpacity
style={styles.button}
>
<Text>Todo</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
>
<Text>Tags</Text>
</TouchableOpacity>
<Text style={styles.text}>{title}</Text>
</View>
</View>
)
}
well you need to track the visiblity of what is visible in your state,
in your App component, do this;
const [showTodos, setShowTodos] = useState(false);
const makeTodosInvisible= () => setShowTodos(false);
const makeTodosVisible = () => setShowTodos(true);
return (
<View>
<Navbar onTodoPress={makeTodosVisible } onTagPress={makeTodosInvisible} title='Todo App!' />
<View style={styles.container}>
{showTodos
? <TodoScreen todos={todos} addTodo={addTodo} removeTodo={removeTodo} />
: <TagScreen addTags={addTags} tags={tags} removeTags={removeTags}/>
}
{/* <TodoScreen todos={todos} addTodo={addTodo} removeTodo={removeTodo} /> */}
{/* HERE MUST CHANGED COMPONENTS */}
</View>
</View>
)
and in your navbar.js do this
export const Navbar = ({ title, onTodoPress, onTagPress}) => {
return (
<View style={styles.padding}>
<View style={styles.navbar}>
<TouchableOpacity
style={styles.button}
onPreesed={onTodoPress} // will hide Tags and show Todos
>
<Text>Todo</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPreesed={onTagPress} // will show Tags and hide Todos
>
<Text>Tags</Text>
</TouchableOpacity>
<Text style={styles.text}>{title}</Text>
</View>
</View>
)
}
I am building a form in a React Native app using Formik.
The form doesn't fire the handleSubmit when I click on the button:
<ButtonLoading
loading={isLoading || isSubmitting}
label="Salvar"
style={styles.button}
onPress={handleSubmit}
/>
Here is my full code for this form:
import React, { Component, Fragment } from 'react';
import { View, ScrollView } from 'react-native';
import { withFormik } from 'formik';
class Form extends Component {
state = {
isCepChecked: false,
isLoading: false,
isNewAddress: true,
};
onChangeCep = () => {
// Not related to the problem
};
render() {
const { isCepChecked, isLoading } = this.state,
{
values,
errors,
touched,
setFieldValue,
setFieldTouched,
handleSubmit,
isSubmitting,
} = this.props;
return (
<View style={styles.container}>
<ScrollView style={styles.formContainer}>
{!isCepChecked ? (
<Fragment>
<View style={styles.lineContent}>
<InputComponent
label="Digite o CEP"
name="nrCepPre"
value={values.nrCepPre}
error={errors.nrCepPre}
touched={touched.nrCepPre}
onTouch={setFieldTouched}
onChange={setFieldValue}
keyboardType="phone-pad"
mask={'[00000]-[000]'}
/>
</View>
<View style={styles.lineContent}>
<ButtonLoading
isLoading={isLoading || isSubmitting}
label="Avançar"
style={styles.button}
onPress={() => this.onChangeCep()}
/>
</View>
</Fragment>
) : (
<Fragment>
<View style={styles.lineContent}>
<InputComponent
label="CEP"
value={values.nrCep}
mask={'[00000]-[000]'}
editable={false}
/>
</View>
<View style={styles.lineContent}>
<InputComponent
label="Identificação"
name="dsEndereco"
value={values.dsEndereco}
error={errors.dsEndereco}
touched={touched.dsEndereco}
onTouch={setFieldTouched}
onChange={setFieldValue}
/>
</View>
<View style={styles.lineContent}>
<ButtonLoading
loading={isLoading || isSubmitting}
label="Salvar"
style={styles.button}
onPress={handleSubmit}
/>
</View>
</Fragment>
)}
</ScrollView>
</View>
);
}
}
export default withFormik({
mapPropsToValues: (props) => ({
nrCepPre: '',
dsEndereco: '',
nrCep: '',
}),
validationSchema: enderecoSchema,
handleSubmit(values, customObject, bag) {
console.warn('handle');
},
})(Form);
Why not include your handleSubmit() func in your Form class instead by defining it as _hanlderSubmit = (e) = {...} so that there isn't a need for binding it. Then just call it as this._handleSubmit.
You can find more on arrow notation here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
i want to pass a value from activity screen to modal screen. I am trying to open a screen when click on flatlist item an dpass value of item to modal,but it shows my detail before rendering modal screen,Here is my activity screen:-
<FlatList
data={this.state.myListDataSource}
renderItem={this._renderItem}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
keyExtractor={({item,index}) => item+index}
refreshControl={
<RefreshControl
refreshing={this.state.isRefreshing}
onRefresh={this.pullToRefresh}
/>
}
/>
<ListProducts
modalVisibility={this.state.listModalVisibility}
closeModal={() =>
this.setState({listModalVisibility:false})}
listName={this.state.listName}
listId={this.state.listId}
/>
handleListItemPress = (item) => {
this.setState({
listModalVisibility:true,
listName : item.name,
listId : item.list_id
})
showMessage('List Item : '+item.listId)
}
_renderItem = ({item}) => {
return(
<TouchableOpacity onPress={() => this.handleListItemPress(item)}>
<View >
<View>
<View style={{flexDirection:'row',marginBottom:2}}>
<ImageView
image={item.pictures[0]}
style={[{marginRight:2},styles.imageStyle]}
/>
<ImageView
image={item.pictures[1]}
style={[{marginLeft:2},styles.imageStyle]}
/>
</View>
<View style={{flexDirection:'row',marginTop:2}}>
<ImageView
style={[{marginRight:2},styles.imageStyle]}
image={item.pictures[2]}
/>
<ImageView
image={item.pictures[3]}
style={[{marginLeft:2},styles.imageStyle]}
/>
</View>
</View>
<View>
<TextViewNonClickable
textViewText={item.name}
/>
<TextViewNonClickable
textViewText={item.description}
/>
</View>
<Icon
name = 'more-vertical'
type = 'feather'
color = {color.colorWhite}
iconStyle={{padding:8}}
containerStyle = {{position:'absolute',top:8,right:8}}
onPress = {() => {
showMessage('Options')
}}
/>
</View>
</TouchableOpacity>
)}
This is my modal screen where i want to get list item id or name.But that screen shows details on the screen rather than rendering modal screen .
Here is my modal screen :-
export default class ListProducts extends Component {
constructor(props){
super(props)
this.state={
products : [],
refreshing : false,
listId : 256,
listName : props.name
}
}
_renderProducts = ({item}) => {
return(
<Product
image={item.image}
name={item.name}
price={item.price}
discountedPrice={item.discounted_price}
quantityAdded={item.quantity_added}
productId={item.product_id}
stock={item.stock}
/>
)
}
render() {
const {modalVisibility,closeModal,listName,listId} = this.props;
return (
<Modal
animationIn='bounceInRight'
animationOut='bounceOutRight'
isVisible={modalVisibility}
onBackButtonPress={closeModal}
>
<View style={{flex:1,backgroundColor:color.colorWhite}}>
<Header
placement='left'
leftComponent={
<FlatList
data={this.state.products}
renderItem={this._renderProducts}
keyExtractor={(item,index) => item+index}
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this.pullToRefresh}
/>
}
numColumns={3}
style={{paddingLeft:2,paddingRight:2}}
/>
</View>
</Modal>
)
}
}
Step 1: pass props from modal to class.
In modal like:
this.props.setItem(“sunny”)
Step 2: Get that props in class in render method where modal initialised.
<ModalName SetItem={item => console.log(item)} \>
I'm actually using 'Dialog' from 'react-native-simple-dialogs' for popup. It works better for me than 'Modal', but i think the logic is the same.
Here is a simplified example of a edit email popup that works for me:
import React from 'react';
import { StyleSheet, View, TextInput } from 'react-native';
import { Button, Text } from 'native-base';
import { Dialog } from 'react-native-simple-dialogs';
export default class EditEmailPopup extends React.Component {
constructor(props) {
super(props);
this.state = {
isModalVisible: this.props.isModalVisible,
};
}
componentWillUpdate() {
this.state.isModalVisible = this.props.isModalVisible;
}
_updateEmailAndCloseDialog() {
// update some data...
this._onCloseDialog();
}
_onCloseDialog() {
this.setState({ isModalVisible: false});
this.props.client(); //this is a function transfered from parent that controls the visibility of the dialog.
}
render() {
return (
<View>
<Dialog
visible={this.state.isModalVisible}
onTouchOutside={() => this._onCloseDialog()}
>
<View>
<Text style={styles.text}>{'Update Email text'}</Text>
<View style={styles.popupButtons}>
<Button
transparent
style={styles.cancelButton}
onPress={() => this._onCloseDialog()}
>
<Text> {'cancel'} </Text>
</Button>
<Button
style={styles.okButton}
onPress={() => this._updateEmailAndCloseDialog()}
>
<Text> {'ok'} </Text>
</Button>
</View>
</View>
</Dialog>
</View>
);
}
}
Here is how i add my Dialog in the parent view:
{this.state.emailModalVisibility ? (
<EditEmailPopup
isModalVisible={this.state.emailModalVisibility}
client={this.afterClosePopup}
/>
) : null}
while this.state.emailModalVisibility initiated in the constructor in state as 'false'.
function written in parent:
_afterClosePopup = () => {
this.setState({
emailModalVisibility: false
});
};
and binded in the constructor so 'this' will belong to parent:
constructor(props) {
super(props);
this.afterClosePopup = this._afterClosePopup.bind(this);
this.state = {
emailModalVisibility: false
};
}
I have an app that needs to be able to use two drawer navigators, one on the left and on on the right side of the header.
I am at the point where I can get both drawers to open with the slide gesture, however I need to be able to open it programmatically. I have found the navigation.openDrawer() function only works with one of the drawers and not the other because it is only able to use one of the navigation props (whichever comes first) from my drawer navigators.
Below are my rendering functions:
const LeftStack = createStackNavigator(
{
LeftDrawerStack
},
{
navigationOptions: ({navigation}) => ({
headerLeft: (
<TouchableOpacity onPress={() => navigation.openDrawer()}>
<Icon style={{marginLeft: 10}} name='menu'/>
</TouchableOpacity>
)
})
}
);
const RightStack = createStackNavigator(
{
RightDrawerStack
},
{
navigationOptions: ({navigation}) => ({
headerRight: (
<TouchableOpacity onPress={() => navigation.openDrawer()}>
<Icon style={{marginRight: 10}} name='ios-bulb'/>
</TouchableOpacity>
)
})
}
);
export const RouteStack = createStackNavigator(
{
screen: LoginScreen,
navigationOptions: ({navigation}) => ({
header: null
}),
LeftStack,
RightStack
}
);
and here are my drawer routes:
export const LeftDrawerStack = createDrawerNavigator(
{
Dashboard: {
screen: DashboardScreen
},
History: {
screen: HistoryScreen
},
Privacy: {
screen: PrivacyPolicyScreen
},
TermsAndConditions: {
screen: TermsAndConditionsScreen
}
}, {
initialRouteName: 'Dashboard',
contentComponent: LeftDrawerScreen
}
);
export const RightDrawerStack = createDrawerNavigator(
{
LeftDrawerStack,
Settings: {
screen: SettingsScreen
}
}, {
drawerPosition: 'right',
contentComponent: RightDrawerScreen
}
);
Here is a picture of what I have the navigation looking like so far, however both of the hamburger menus are opening up the same menu on the right instead of one menu on their respective sides.
I may be missing some parts but I will be sure to post more info if I forgot any!
I was able to do this with the following setup (try to make changes to your structure to be like this):
const LeftDrawer = createDrawerNavigator(
{
LeftDrawer: MyStackNavigator,
},
{
getCustomActionCreators: (route, stateKey) => { return { toggleLeftDrawer: () => DrawerActions.toggleDrawer({ key: stateKey }) }; },
drawerPosition: 'left',
contentComponent: MyLeftDrawer
}
);
const RightDrawer = createDrawerNavigator(
{
Drawer: LeftDrawer,
},
{
getCustomActionCreators: (route, stateKey) => { return { toggleRightDrawer: () => DrawerActions.toggleDrawer({ key: stateKey }) }; },
drawerPosition: 'right',
contentComponent: MyRightDrawer
}
);
export const RootNavigator = createStackNavigator(
{
Login: Login,
Home: RightDrawer
},
{
initialRouteName: 'Login',
navigationOptions: { header: null, gesturesEnabled: false }
}
);
The key is getCustomActionCreators. It allows you to call the function from any screen in MyStackNavigator like this: this.props.navigation.toggleLeftDrawer();.
This is solution I do
Step 1: Create two drawer navigation and nest them together
Step 2: Store first drawer navigation in other place (Singleton)
// Drawer 1
import ContentLeftMenu from '#components/ContentLeftMenu';
import { createDrawerNavigator } from '#react-navigation/drawer';
import * as React from 'react';
import DrawerCart from './DrawerCart';
import { setNavigationDrawerHome } from './RootNavigation';
import { isTablet } from 'react-native-device-info';
import MainStack from './MainStack';
const Drawer = createDrawerNavigator();
export default function DrawerHome() {
return (
<Drawer.Navigator
initialRouteName="DrawerCart"
drawerContent={() => <ContentLeftMenu />}
screenOptions={({ navigation, route }) => {
setNavigationDrawerHome(navigation)
}}
>
<Drawer.Screen name="DrawerCart" component={isTablet ? DrawerCart : MainStack} />
</Drawer.Navigator>
);
}
// Drawer 2
import CartScreen from '#features/cart/CartScreen';
import { createDrawerNavigator } from '#react-navigation/drawer';
import * as React from 'react';
import MainStack from './MainStack';
const Drawer = createDrawerNavigator();
export default function DrawerCart(props) {
return (
<Drawer.Navigator
initialRouteName="MainStackCart"
drawerContent={() => <CartScreen />}
drawerPosition='right'
>
<Drawer.Screen name="MainStackCart" component={MainStack} />
</Drawer.Navigator>
);
}
// set navigation of drawer 1 with navigationDrawerHome
let navigationDrawerHome = null
export const setNavigationDrawerHome = (navigation) => {
navigationDrawerHome = navigation
}
export const getNavigationDrawerHome = () => {
return navigationDrawerHome
}
And when I use in Mainstack I when open Drawer 1 in left I use navigationDrawerHome, with drawer 2 just use navigation props
const Stack = createStackNavigator();
function MainStack() {
const navigationDrawerHome = getNavigationDrawerHome()
return (
<Stack.Navigator
screenOptions={({ navigation, route }) => ({
headerLeft: () => <HeaderLeft />,
headerTitleAlign: 'center',
})}>
<Stack.Screen
name="home_user_tab"
component={HomeUserTabs}
options={({ navigation, route }) => ({
headerLeft: () => {
return (
<ButtonIcon
onPress={() => navigationDrawerHome.openDrawer()}
style={styles.buttonLeft}
icon={images.ic_left_menu}
/>
)
},
headerTitle: () => <LogoHeader />,
headerRight: () => (<HeaderCardSearch
navigation={navigation}
/>),
// header: null
})}
/>
</Stack.Navigator>
);
}
const HeaderCardSearch = (props) => {
const { navigation } = props;
return (
<View style={styles.headerRight}>
<ButtonIcon
onPress={() => navigation.openDrawer()}
style={styles.buttonCart}
icon={images.ic_cart}
/>
<ButtonIcon
onPress={() => navigate('search')}
style={styles.buttonSearch}
icon={images.ic_search}
/>
</View>
)
};
I managed to programmatically open both drawers this way:
// Opens left drawer
this.props.navigation.openDrawer();
// Opens right drawer
this.props.navigation.dangerouslyGetParent().dangerouslyGetParent().openDrawer();
And my navigation container looks like this:
static container = (): NavigationContainer => createDrawerNavigator({
right: createDrawerNavigator({
left: DeviceControlContainer
}, {
contentComponent: HistoryDrawerContainer,
overlayColor: drawerOverlayColor()
})
}, {
drawerPosition: 'right',
overlayColor: drawerOverlayColor(),
navigationOptions: DeviceControlScreen.navigationOptions,
contentComponent: DeviceControlDrawer
});
Got inspired from Anh Devit solution, here is mine. I'm using a header bar across the app without a Stack Navigator, so had to go a slightly different route.
For my RootNavigator, I put my Header above my first drawer. I use useState so when I pass down the navigation objects as props, the AppHeader can re-render correctly when the Drawers have been initialized.
import React, { useState } from "react";
import { NavigationContainer } from "#react-navigation/native";
import LeftDrawer from "./LeftDrawer";
import AppHeader from "./AppHeader";
const RootNavigator = () => {
const [navigationLeftDrawer, setNavigationLeftDrawer] = useState(null);
const [navigationRightDrawer, setNavigationRightDrawer] = useState(null);
return (
<NavigationContainer>
<AppHeader
navigationLeftDrawer={navigationLeftDrawer}
navigationRightDrawer={navigationRightDrawer}
/>
<LeftDrawer
navigationLeftDrawer={(navigation) =>
setNavigationLeftDrawer(navigation)
}
navigationRightDrawer={(navigation) =>
setNavigationRightDrawer(navigation)
}
/>
</NavigationContainer>
);
};
export default RootNavigator;
Here I'm creating my LeftDrawer, in which the RightDrawer will be nested. Notice setting the navigationLeftDrawer when the Drawer inits. Also, navigationRightDrawerhas to be passed down as a param and not a prop.
import React, { useContext } from "react";
import {
createDrawerNavigator,
DrawerContentScrollView,
DrawerItem,
} from "#react-navigation/drawer";
import RightDrawer from "./RightDrawer";
const LeftDrawer = ({ navigationLeftDrawer, navigationRightDrawer }) => {
const Drawer = createDrawerNavigator();
return (
<Drawer.Navigator
screenOptions={({ navigation }) => {
navigationLeftDrawer(navigation);
}}
drawerContent={(props) => {
const { navigate } = props.navigation;
return (<RightDrawerItems />)
);
}}
>
<Drawer.Screen
name="AccountDrawer"
component={RightDrawer}
initialParams={{ navigationRightDrawer }}
/>
</Drawer.Navigator>
);
export default LeftDrawer;
Likewise in RightDrawer, passing up navigationRightDrawer with the right navigation object.
import React from "react";
const RightDrawer = ({ route }) => {
const Drawer = createDrawerNavigator();
const { navigationRightDrawer } = route.params;
return (
<Drawer.Navigator
drawerPosition="right"
screenOptions={({ navigation }) => {
navigationRightDrawer(navigation);
}}
drawerContent={(props) => {
const { navigate } = props.navigation;
return ( <RightDrawerItems />);
}}
>
{userAuth ? (
<>
<Drawer.Screen name={routes.dashboard} component={DashboardScreen} />
</>
) : (
<Drawer.Screen name={routes.home} component={HomeStack} />
)}
<Drawer.Screen name={routes.about} component={AboutScreen} />
<Drawer.Screen name={routes.language} component={LanguageScreen} />
</Drawer.Navigator>
);
};
export default RightDrawer;
Finally, the AppHeader :
import React, { useContext } from "react";
const AppHeader = ({ navigationRightDrawer, navigationLeftDrawer }) => {
if (navigationRightDrawer == null || navigationLeftDrawer == null)
return null;
return (
<View style={styles.container}>
<Icon
name="menu"
color={colors.white}
onPress={() => {
navigationRightDrawer.closeDrawer();
navigationLeftDrawer.toggleDrawer();
}}
/>
{userAuth ? (
<TouchableWithoutFeedback
onPress={() => {
navigationLeftDrawer.closeDrawer();
navigationRightDrawer.toggleDrawer();
}}
>
<Image
style={styles.image}
source={{ uri: userProfile.profilePicture }}
/>
</TouchableWithoutFeedback>
) : (
<Icon
name="person"
color={colors.secondary}
onPress={() => navigationLeftDrawer.navigate(routes.login)}
/>
)}
</View>
);
};
export default AppHeader;