Why is 'this.props.navigation' unavailable to screen component? - react-native

I have a drawer navigator that has a stack navigator nested inside it as one of the screen options. I have no issues navigating to any screens in the drawer, but when I try to navigate to another screen in the stack navigator, I dont have access to this.props.navigation. Im confused because the screen is declared in my navigator setup.
AppNavigator:
// all imports
const InboxStack = createStackNavigator(
{
Inbox: {
screen: HomeScreen
},
Conversation: {
screen: ConversationScreen
}
},
{
headerMode: "none",
initialRouteName: "Inbox"
}
);
const MainNavigator = createDrawerNavigator(
{
Inbox: InboxStack,
Second: { screen: SecondScreen },
Third: { screen: ThirdScreen }
},
{
drawerPosition: "left",
initialRouteName: "Inbox",
navigationOptions: ({ navigation }) => ({
title: "Drawer Navigator Header",
headerTitleStyle: {
color: "blue"
},
headerLeft: <Text onPress={() => navigation.toggleDrawer()}>Menu</Text>
})
}
);
const WrapperStackNavigator = createStackNavigator({
drawerNav: MainNavigator
});
const AppContainer = createAppContainer(
createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: WrapperStackNavigator,
Login: LoginScreen,
Register: RegisterScreen
},
{
initialRouteName: "AuthLoading"
}
)
);
export default AppContainer;
utilization of navigation prop in ConversationScreen:
import React from "react";
import { View, Text } from "react-native";
import { connect } from "react-redux";
import { loadConversation } from "../actions";
import MessagesList from "../components/MessagesList.js";
class ConversationScreen extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
this.loadConversation();
}
loadConversation() {
this.props.loadConversation(
this.props.navigation.state.params.convoId // this works!
this.props.navigation.getParams("convoId") // this does not :(
);
}
render() {
return (
<View
style={{
display: "flex",
alignItems: "center",
justifyContent: "center"
}}
>
<Text>Conversation screen</Text>
<MessagesList messages={this.props.messages} />
</View>
);
}
}
const mapStateToProps = ({ conversation, auth }) => {
const { messages } = conversation;
const { user } = auth;
return { messages, user };
};
const mapDispatchToProps = {
loadConversation
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(ConversationScreen);
The issue exists with ConversationScreen, I dont have access to the navigation prop, but docs say if its declared in the navigator it should be be passed the navigation prop. Every call using this.props.navigation errors with ... is not a function, ... is undefined
... being this.props.navigation.navigate, this.props.navigation.getParams, etc

After checking the props object through alert(this.props) I verified I had access to the navigation object, even though it appeared to be undefined, ultimately using
componentDidMount() {
loadConversation() {
this.props.loadConversation(
this.props.navigation.state.params.convoId
);
}
}
This got me where I needed to be. although it would have been nice to just use this.props.navigation.getParams()

Related

How to use hook with SwitchNavigator

I'm trying to use https://github.com/expo/react-native-action-sheet with switch navigator.
I'm not sure how to do the basic setup as the example in the readme is different than my App.js. I'm using react 16.8 so I should be able to use hooks.
My App.js
import { useActionSheet } from '#expo/react-native-action-sheet'
const AuthStack = createStackNavigator(
{ Signup: SignupScreen, Login: LoginScreen }
);
const navigator = createBottomTabNavigator(
{
Feed: {
screen: FeedScreen,
navigationOptions: {
tabBarIcon: tabBarIcon('home'),
},
},
Profile: {
screen: ProfileScreen,
navigationOptions: {
tabBarIcon: tabBarIcon('home'),
},
},
},
);
const stackNavigator = createStackNavigator(
{
Main: {
screen: navigator,
// Set the title for our app when the tab bar screen is present
navigationOptions: { title: 'Test' },
},
// This screen will not have a tab bar
NewPost: NewPostScreen,
},
{
cardStyle: { backgroundColor: 'white' },
},
);
export default createAppContainer(
createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: stackNavigator,
Auth: AuthStack,
},
{
initialRouteName: 'AuthLoading',
}
);
const { showActionSheetWithOptions } = useActionSheet();
);
Update, I'm getting this error when calling the showActionSheetWithOptions inside my component:
Hooks can only be called inside the body of a function component. invalid hook call
This is my code:
import React, { Component } from 'react';
import { useActionSheet } from '#expo/react-native-action-sheet'
export default class NewPostScreen extends Component {
_onOpenActionSheet = () => {
const options = ['Delete', 'Save', 'Cancel'];
const destructiveButtonIndex = 0;
const cancelButtonIndex = 2;
const { showActionSheetWithOptions } = useActionSheet();
showActionSheetWithOptions(
{
options,
cancelButtonIndex,
destructiveButtonIndex,
},
buttonIndex => {
console.log(buttonIndex);
},
);
};
render () {
return (
<View>
<Button title="Test" onPress={this._onOpenActionSheet} />
</View>
)
}
}
update 2
I also tried using a functional component, but the actionsheet does not open (console does print "pressed")
// ActionSheet.js
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
import { useActionSheet } from '#expo/react-native-action-sheet'
export default function ActionSheet () {
const { showActionSheetWithOptions } = useActionSheet();
const _onOpenActionSheet = () => {
console.log("pressed");
const options = ['Delete', 'Save', 'Cancel'];
const destructiveButtonIndex = 0;
const cancelButtonIndex = 2;
showActionSheetWithOptions(
{
options,
cancelButtonIndex,
destructiveButtonIndex,
},
(buttonIndex) => {
console.log(buttonIndex);
},
);
};
return (
<TouchableOpacity onPress={_onOpenActionSheet} style={{height: 100,}}>
<Text>Click here</Text>
</TouchableOpacity>
);
};
Problem
As you can see here. You are not connecting your application root component.
Solution
import connectActionSheet from #expo/react-native-action-sheet and connect your application root component to the action sheet.
Simply modify your App.js to reflect the following:
// ... Other imports
import { connectActionSheet } from '#expo/react-native-action-sheet'
const AuthStack = createStackNavigator({
Signup: SignupScreen,
Login: LoginScreen
});
const navigator = createBottomTabNavigator({
Feed: {
screen: FeedScreen,
navigationOptions: {
tabBarIcon: tabBarIcon('home'),
},
},
Profile: {
screen: ProfileScreen,
navigationOptions: {
tabBarIcon: tabBarIcon('home'),
},
},
});
const stackNavigator = createStackNavigator({
Main: {
screen: navigator,
// Set the title for our app when the tab bar screen is present
navigationOptions: { title: 'Test' },
},
// This screen will not have a tab bar
NewPost: NewPostScreen,
}, {
cardStyle: { backgroundColor: 'white' },
});
const appContianer = createAppContainer(
createSwitchNavigator({
AuthLoading: AuthLoadingScreen,
App: stackNavigator,
Auth: AuthStack,
}, {
initialRouteName: 'AuthLoading',
})
);
const ConnectApp = connectActionSheet(appContianer);
export default ConnectApp;
Now on any of your application screens (i.e. Feed, Profile, Main, etc.) you can access the action sheet as follows:
If Stateless Component
// ... Other imports
import { useActionSheet } from '#expo/react-native-action-sheet'
export default function Profile () {
const { showActionSheetWithOptions } = useActionSheet();
/* ... */
}
If Statefull Component
// ... Other imports
import React from 'react'
import { useActionSheet } from '#expo/react-native-action-sheet'
export default Profile extends React.Component {
const { showActionSheetWithOptions } = useActionSheet();
/* ... */
}
Note: You can also access the action sheet as stated below from the docs
App component can access the actionSheet method as this.props.showActionSheetWithOptions

How can I create createDrawerNavigator inside createStackNavigator in React native?

I'm using react-navigation v3 for react native app.
When I createDrawerNavigator inside createStackNavigator I can't openDrawer but if I createDrawerNavigator in root navigator I can open it.
Here is my code. Anyone have a solution for me?
AppNavigator.js
const AppNavigator = createSwitchNavigator(
{
StackNavigatorMain: StackNavigatorMain,
StackMenu: StackMenu
},
{
headerMode: "null",
navigationOptions: {
headerVisible: false
},
initialRouteName: "StackNavigatorMain"
}
);
export default createAppContainer(AppNavigator);
StackNavigatorMain.js
const StackNavigatorMain = createStackNavigator(
{
routeHome: Home,
routeLogin: Login,
routeForgotPassword: ForgotPassword,
routeSignUp: SignUp,
},
{
headerMode: "none",
initialRouteName: strings.routeHome,
}
)
export default StackNavigatorMain
StackMenu.js
const StackMenu = createStackNavigator({
//Drawer Optons and indexing
MenuNavigator: MenuNavigator,
},
{
headerMode: "null",
navigationOptions: {
headerVisible: false
},
}
);
export default StackMenu;
MenuNavigator.js
const MenuNavigator = createDrawerNavigator({
//Drawer Optons and indexing
Setting: Setting
},
{
drawerWidth: responsiveWidth(180),
overlayColor: 'transparent',
// drawerLockMode: 'locked-open',
contentComponent: AppSideMenu
}
);
export default MenuNavigator;
index.js
export default class App extends Component {
render() {
return (
<AppNavigator/>
);
};
}
Call open drawer onPress button in Component screen
onClicked = () => {
// props.navigation.openDrawer();
props.navigation.dispatch(DrawerActions.openDrawer());
}

Stack Navigator not showing the screens

So I've been trying to get the stack navigator to work. According to the console.log('Main') I do actually enter the main screen. Which is what I want. However, the screen just gives me a blank screen with only the header showing. I have no idea what the issue is. I thought it could be with the styling but I've deleted and changed it and nothing seems to be working as well. How I have been navigating was simply doing < ScreenName />. But that won't work because I'm trying to navigate around with buttons as well.
Screenshot of login
Main
App.js
renderComponent() {
if (this.state.loggedIn) {
return (
<Container />
)
} else {
return (
<LoginForm />
)
}
}
render() {
return (
<View>
<Header title='InTouch' />
{this.renderComponent()}
</View>
);
}
}
Screen Container
import React, { Component } from 'react';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import { View, Button } from 'react-native';
import Main from './src/components/Main'
import Upload from './src/components/Upload'
const NavigationStack = createStackNavigator({
Main: {screen: Main },
Upload: {screen: Upload},
},{
navigationOptions: {
gesturesEnabled:false
}
})
const Container = createAppContainer(NavigationStack);
export default Container;
Main.js
export default class Main extends Component<Props> {
state = { currentUser: null}
componentDidMount() {
const { currentUser } = firebase.auth()
this.setState({ currentUser })
}
render() {
console.log("Main")
const { currentUser } = this.state
return (
<View>
<Text>Hello</Text>
<Button title = "Go to upload story" onPress = {() => this.props.navigation.navigate('Upload')} />
<Button
title="Sign out"
onPress={() => firebase.auth().signOut()} />
</View>
);
I just want the Main to show up.
Login screen should be under the stack navigation, and after logging in you can navigate to other screen
try doing it like this
const NavigationStack = createStackNavigator({
Login: {screen: Login }
Main: {screen: Main },
Upload: {screen: Upload},
},{
navigationOptions: {
gesturesEnabled:false
}
})
alternatively you can create separate navigation for login and other screens using switch
const HomeNavigation = createStackNavigator({
Main: {screen: Main },
Upload: {screen: Upload},
},{
navigationOptions: {
gesturesEnabled:false
}
})
const RootNavigation = createSwitchNavigator({
Login: {screen: Login }
Home: {screen: HomeNavigation }
});
and in App.js do
render() {
return (
<RootNavigation/>
);
}

Adding tab component in a view

I am new to react native, and I am struggling to understand it. This may be a very basic question.
I have a screen and it consists of a searchbar on top of the page and below it there are Tabs. While navigating through the tabs, the searchbar should not be removed (being at the top level).
MainScreen:
export default class MainScreen extends Component {
render() {
return (
<View>
<Text>My search bar here</Text>
<TabBar></TabBar>
</View>
);
}
}
TabBar:
const routeConfiguration = {
TabEvents: { screen: TabEvents },
TabPeople: { screen: TabPeople },
TabGroups: { screen: TabGroups },
TabMap: { screen: TabMap },
}
const tabBarConfiguration = {
tabBarOptions:{
// some options
}
}
export const TabBar = TabNavigator(routeConfiguration,tabBarConfiguration)
When running the app, only the text is being displayed My search bar here without the tabs.
To be able to show tabs, the navigator acts like a container with "two views". One is for the screens that you wanna show and, at the bottom, the tabs container.
So, for the MainScreen you just only need to define the tabs/screens that want react navigator to render.
In each screen you will put the header as shown above. You could also define a default header in the navigator props.
MainScreen.js:
const MainScreen = TabNavigator({
TabEvents: { screen: TabEvents },
Second: { screen: SecondPage },
Third: { screen: ThirdPage },
Fourth: { screen: FourthPage },
Fifth: { screen: FifthPage }
}
})
export default MainScreen;
MainScreen.js: (with default header)
const MainScreen = TabNavigator({
TabEvents: { screen: TabEvents },
Second: { screen: SecondPage },
Third: { screen: ThirdPage },
Fourth: { screen: FourthPage },
Fifth: { screen: FifthPage }
}, {
navigationOptions: {
header: <YourHeader />
}
})
export default MainScreen;
TabEvents.js
export default class TabEvents extends Component {
render() {
return (
<View>
<YourHeader />
<MoreStuff/>
</View>
);
}
}
You wil have a more detailed example in the docs ( https://github.com/react-community/react-navigation/blob/master/examples/NavigationPlayground/js/SimpleTabs.js & https://reactnavigation.org/docs/navigators/tab)
You can wrap your TabNavigator with StackNavigator.
MyTabNavigator.js
const MyTabNavigator = TabNavigator({
ScreenX: { screen: SceenNameX },
ScreenY: { screen: ScreenNameY }
}, {
initialRouteName: 'ScreenX',
tabBarPosition: 'top',
tabBarOptions: {
activeTintColor: '#af0'
}
})
export default MyTabNavigator
MainScreen.js
export default class MainScreen extends Component {
static navigationOptions = {
header: (props) => (
<SearchBar {...props}/>
)
}
render() {
return (
<MyTabNavigator />
)
}
}
MyStackNavigator.js
const MyStackNavigator = StackNavigator({
Main: { screen: MainScreen }
}, {
initialRouteName: 'Main'
})
export default MyStackNavigator
Now you can call MyStackNavigator to load MainScreen which will render the header SearchBar and the body MyTabNavigator.
The way to create a Tab navigator is the following:
tabNavigator.js
import React from 'react'
import { Platform } from 'react-native'
import { TabNavigator, StackNavigator } from 'react-navigation'
const Tabs = TabNavigator({
Home:{ //this is the name of the screen, by default the first screen that you want to show is called Home
screen: component , //this is the component that you want to show in the screen
navigationOptions: {
tabBarLabel: 'some label', //this will be located as a title for the tab
tabBarIcon: ({ tintColor }) => <i> some icon </i>, //this allow you to show a icon in the tab
//the following options are to customize the header, maybe you don't need this.
title: 'some title',
headerStyle:{
backgroundColor: 'blue' // color for the header
},
headerTitleStyle:{
color: 'white' // color for the text on the header
},
header: <YourHeader/>
}
},
// if you need add some other tab repeat the same pattern here OtherScreen:{ ...}
},{
//this are options to customize the tab itself, I added some good ones.
tabBarOptions: {
activeTintColor: Platform.OS === 'ios' ? primary : white,
style:{
height:40,
backgroundColor: Platform.OS === 'ios' ? white : primary,
shadowRadius: 6,
shadowOpacity: 1,
shadowColor: 'rgba(0,0,0,0.24)',
shadowOffset: {
width: 0,
height: 3
}
}
}
})
export default Tabs
mainScreen.js
import React, { Component} from 'react'
import Tabs from './tabNavigator'
export default class MainScreen extends Component {
render() {
return (
<View>
<Tabs/>
</View>
);
}
}
I hope it helps.

How to detect when the drawer is opened in react-navigation?

I'm using react-navigation's DrawerNavigator in my app. I would like to detect when a user drags open the side menu so that i can perform a certain action, e.g dismiss an opened Keyboard.
How can i do this? i can't seem to find a solution in the docs. Thank you.
Here is my code
import React from 'react';
import { Dimensions } from 'react-native';
import { Icon } from 'react-native-elements';
import { DrawerNavigator, StackNavigator, addNavigationHelpers } from 'react-navigation';
//redux related imports
import { createStore, combineReducers } from 'redux';
import { Provider, connect } from 'react-redux';
import Attendance from './containers/pages/Attendance';
import Fees from './containers/pages/Fees';
import Exams from './containers/pages/Exams';
import InitializeUser from './containers/pages/InitializeUser';
import Landing from './Landing';
import Login from './containers/pages/Login';
import Search from './containers/pages/Search';
import Staff from './containers/pages/Staff';
import Stats from './containers/pages/Stats';
import Students from './containers/pages/Students';
import Verification from './containers/pages/verify';
import ProfileDetail from './components/pages/ProfileDetail';
import FeesDetail from './containers/pages/FeesDetails';
import MainReport from './containers/pages/Reports/Main_Report';
import AcademicDetails from './containers/pages/Reports/Student_Academic_Details';
import { Constants } from './config';
import ResultsLanding from './containers/pages/Reports/ResultsLanding';
import { CustomDrawerContentComponent } from '../src/components/base/SideMenu';
const screenWidth = Dimensions.get('window').width;
const MainPages = DrawerNavigator({
StudentsPage: {
path: '/Students',
screen: Students
},
SearchPage: {
path: '/Seacrh',
screen: Search
},
Staff: {
path: '/Staff',
screen: Staff
},
Fees: {
path: '/Fees',
screen: Fees
},
Stats: {
path: '/Stats',
screen: Stats
},
Results: {
screen: ResultsLanding,
navigationOptions: {
tintColor: 'red',
flex: 1,
drawerIcon: ({ tintColor }) => (
<Icon
name="content-paste"
color={tintColor}
/>
)
}
},
Attendance:
{
path: '/Attendance',
screen: Attendance
},
},
{
initialRouteName: 'StudentsPage',
contentOptions: {
activeTintColor: Constants.ui.THEME,
activeBackgroundColor: 'rgba(0,0,0,0.1)',
inactiveTintColor: 'rgba(0,0,0,0.6)',
labelStyle: {
fontSize: 12,
marginLeft: 10,
},
},
drawerWidth: screenWidth > 320 ? 300 : 250,
contentComponent: CustomDrawerContentComponent
});
export const Navigator = StackNavigator({
LandingPage: {
screen: Landing,
navigationOptions: {
header: null
}
},
LoginPage: {
screen: Login,
navigationOptions: {
header: null
},
},
ProfileDetailPage: {
screen: ProfileDetail,
headerMode: 'screen',
navigationOptions: {
header: null
}
},
FeesDetailPage:
{
screen: FeesDetail,
navigationOptions: {
header: null
},
},
VerifyPage: {
screen: Verification,
navigationOptions: {
header: null
},
},
InitUserPage: {
screen: InitializeUser,
navigationOptions: {
header: null
},
},
MainPages: {
screen: MainPages,
navigationOptions: {
header: null
}
},
MainReportPage: {
screen: MainReport,
navigationOptions: {
header: null
}
},
ExamsMainPage: {
screen: Exams,
navigationOptions: {
header: null
}
},
AcademicDetailsPage: {
screen: AcademicDetails,
navigationOptions: {
header: null
}
},
});
const initialState = MainPages.router.getStateForAction(
MainPages.router.getActionForPathAndParams('StudentsPage'));
const navReducer = (state = initialState, action) => {
const nextState = MainPages.router.getStateForAction(action, state);
return nextState || state;
};
const appReducer = combineReducers({
nav: navReducer
});
class App extends React.Component {
componentWillReceiveProps(nextProps) {
console.warn('nextProps: ', JSON.stringify(nextProps, null, 4));
}
render() {
return (
<MainPages
navigation={addNavigationHelpers({
dispatch: this.props.dispatch,
state: this.props.nav,
})} />
);
}
}
const mapStateToProps = (state) => ({
nav: state.nav
});
const AppWithNavigationState = connect(mapStateToProps)(App);
const store = createStore(appReducer);
class Root extends React.Component {
render() {
return (
<Provider store={store}>
<AppWithNavigationState />
</Provider>
);
}
}
Here is a screenshot of the error i get when i run the code
Simply, if you use react-navigation v5 -
import { useIsDrawerOpen } from '#react-navigation/drawer'
const isOpen: boolean = useIsDrawerOpen()
then you have to subscribe on "isOpen" flag by hook useEffect:
useEffect(() => {
if (!isOpen) {
// Your dismiss logic here
}
}, [isOpen])
Your custom Drawer can look like DrawerContent
Hope it helped
I was able to detect the DrawerNavigator's open and close side menu actions by following the Redux Integration guide and modifying it to use a DrawerNavigator instead of StackNavigator. Here is what I have inside my index.ios.js file. Near the bottom within the App class I use componentWillReceiveProps which displays a warning every time the drawer opens or closes.
import React from 'react';
import {
AppRegistry,
Image,
Text,
View,
ScrollView
} from 'react-native';
import {DrawerNavigator, DrawerItems, addNavigationHelpers } from 'react-navigation';
import { Provider, connect } from 'react-redux'
import { createStore, combineReducers } from 'redux'
class MyHomeScreen extends React.Component {
static navigationOptions = {
drawerLabel: 'Home',
drawerIcon: ({ tintColor }) => (
<Image
source={require('./images/Groups.png')}
style={{tintColor: tintColor, width: 26, height: 26}}/>
),
};
render() {
return (
<View>
<Text>Home Screen</Text>
</View>
);
}
}
class MyNotificationsScreen extends React.Component {
static navigationOptions = {
drawerLabel: 'Notifications',
drawerIcon: ({ tintColor }) => (
<Image
source={require('./images/Events.png')}
style={{tintColor: tintColor, width: 26, height: 26}}/>
),
};
render() {
return (
<View>
<Text>Notifications Screen</Text>
</View>
);
}
}
const NavDemo = DrawerNavigator({
Home: { screen: MyHomeScreen },
Notifications: { screen: MyNotificationsScreen }
}, {
tabBarOptions: {
activeTintColor: '#e91e63',
},
drawerWidth: 200,
drawerPosition: 'left',
contentComponent: props => <ScrollView><DrawerItems {...props} /></ScrollView>
});
const initialState = NavDemo.router.getStateForAction(NavDemo.router.getActionForPathAndParams('Home'));
const navReducer = (state = initialState, action) => {
const nextState = NavDemo.router.getStateForAction(action, state);
return nextState || state;
};
const appReducer = combineReducers({
nav: navReducer
});
class App extends React.Component {
componentWillReceiveProps(nextProps) {
console.warn('nextProps: ' + JSON.stringify(nextProps, null, 4))
}
render() {
return (
<NavDemo navigation={addNavigationHelpers({
dispatch: this.props.dispatch,
state: this.props.nav,
})} />
);
}
}
const mapStateToProps = (state) => ({
nav: state.nav
});
const AppWithNavigationState = connect(mapStateToProps)(App);
const store = createStore(appReducer);
class Root extends React.Component {
render() {
return (
<Provider store={store}>
<AppWithNavigationState />
</Provider>
);
}
}
AppRegistry.registerComponent('NavDemo', () => Root);
When I open the drawer and expand the warning nextProps looks like this:
And then after I close the drawer, the new warning appears like this:
nextProps.nav is an object with two keys, routes and index. When the drawer opens, index becomes 1, and when it closes, index becomes 0.
Using that information, you can add an if statement to perform your necessary actions when the drawer opens.
This is an old thread, but I wanted to share how I managed to do this.
Add the following code inside your app (preferably where you create the DraweStack.)
const defaultGetStateForAction = DrawerStack.router.getStateForAction;
DrawerStack.router.getStateForAction = (action, state) => {
switch (action.type) {
case "Navigation/DRAWER_OPENED":
case "Navigation/MARK_DRAWER_ACTIVE":
Keyboard.dismiss();
break;
}
return defaultGetStateForAction(action, state);
};
There are various action.types. For instance:
Navigation/MARK_DRAWER_ACTIVE is called when the drawer starts to open
Navigation/MARK_DRAWER_SETTLING is called when the drawer has opened.
etc.
Cheers.
this.props.navigation.state.isDrawerOpen => true/false
In navigation 6x, you can do the following to get the drawer status.
import { useDrawerStatus } from '#react-navigation/drawer';
const isDrawerOpen = useDrawerStatus() === 'open';
here is the full documentation. https://reactnavigation.org/docs/drawer-navigator/#events