StackNavigator and TabNavigaor is deprecated in react-native - react-native

In my project, after updating node modules, react navigation showed some issues. In the console it says,
The tabBarBottom is deprecated. Use react-navigation-tabs package.
stackNavigator function name is deprecated. Use createStackNavigator
tabNavigator is deprecated. Use createBottomTabNavigator
import React from "react";
import { StackNavigator } from "react-navigation";
import { TabNavFooter } from "./TabNavFooter";
import { SIGNIN_KEY, SIGNUP_KEY } from "../config/routeKeys";
import {
SignupScreen,
SigninScreen,
MainFeedScreen,
CommentScreen,
SharePostScreen
} from "../screens";
export const Routes = StackNavigator({
mainfeed: { screen: TabNavFooter },
signin: { screen: SigninScreen },
signup: { screen: SignupScreen },
comments: { screen: CommentScreen },
sharePost: { screen: SharePostScreen }
});
import React from "react";
import { TabNavigator, TabBarBottom } from "react-navigation";
import { ClickableImage, ClickableIcon } from "../mixing/UI";
import TAB_NAVIGATOR_IMAGES from "../config/tabNavImgs";
import { Image } from "react-native";
import {
MainFeedScreen,
WorkoutScreen,
VideosScreen,
ChatScreen,
ProfileMainScreen
} from "../screens";
export const TabNavFooter = TabNavigator(
{
mainfeed: { screen: MainFeedScreen },
workout: { screen: WorkoutScreen },
video: { screen: VideosScreen },
chat: { screen: ChatScreen },
profile: { screen: ProfileMainScreen }
},
{
navigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, tintColor }) => {
const { routeName } = navigation.state;
let imageSource;
if (routeName === "mainfeed") {
imageSource =
TAB_NAVIGATOR_IMAGES[
`${focused ? "mainfeedActive" : "mainfeedInactive"}`
];
} else if (routeName === "workout") {
imageSource =
TAB_NAVIGATOR_IMAGES[
`${focused ? "workoutActive" : "workoutInactive"}`
];
} else if (routeName === "video") {
imageSource =
TAB_NAVIGATOR_IMAGES[
`${focused ? "videoActive" : "videoInactive"}`
];
} else if (routeName === "chat") {
imageSource =
TAB_NAVIGATOR_IMAGES[`${focused ? "chatActive" : "chatInactive"}`];
} else if (routeName === "profile") {
imageSource =
TAB_NAVIGATOR_IMAGES[
`${focused ? "profileActive" : "profileInactive"}`
];
}
return (
<Image
source={imageSource}
style={{
width: 25,
height: 25,
tintColor: tintColor,
marginBottom: 0
}}
/>
);
}
}),
tabBarComponent: TabBarBottom,
tabBarPosition: "bottom",
tabBarOptions: {
activeTintColor: "blue",
inactiveTintColor: "gray"
},
swipeEnabled: false,
lazyLoad: true,
animationEnabled: false
}
);
How can I solve these errors?

It's due to upgrade in react-navigation version. you have probably upgraded to v2 of the package.
They have documentation for that version but still not complete and lack in some minute details. you can see the doc in this link
the configuration differs between v1 and v2. you could manage to get v2 work with some difficulties. you can ask specific difficulties you face in that process here or in some other question. But if you find still tough, you can move back to lower version which is well documented.

Replace StackNavigator with createStackNavigator. And TabNavigator with createBottomTabNavigator.
TabBarBottom I have not used yet, but it looks like it was put into its own package called react-navigation-tabs that needs to be installed and pulled from there instead.

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

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

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()

react navigation v3 cannot read property 'default' of undefined

I'm trying to define the navigation in my app in react native but I get a weird error.
the root stack on an app
import React from 'react'
import { Easing, Animated } from 'react-native'
import { createAppContainer, createStackNavigator, createSwitchNavigator } from 'react-navigation'
import { UserStore } from '../stores'
import { Playground, Welcome, Login, Register, ConfirmationCode, App, AuthLoading } from '../screens'
// import TabStack from './TabStack'
const transitionConfig = () => {
return {
transitionSpec: {
duration: 750,
easing: Easing.out(Easing.poly(4)),
timing: Animated.timing,
useNativeDriver: true,
},
screenInterpolator: sceneProps => {
const { layout, position, scene } = sceneProps
const thisSceneIndex = scene.index
const width = layout.initWidth
const translateX = position.interpolate({
inputRange: [thisSceneIndex - 1, thisSceneIndex],
outputRange: [width, 0],
})
return { transform: [{ translateX }] }
},
}
}
const AuthStack = createStackNavigator(
{
Welcome,
Login,
Register,
ConfirmationCode,
},
{
initialRouteName: 'Welcome',
headerMode: 'none',
lazy: true,
transitionConfig,
defaultNavigationOptions: {
gesturesEnabled: false,
},
}
)
let MainStack = createSwitchNavigator(
{
AuthLoading,
Auth: AuthStack,
App,
},
{
initialRouteName: 'AuthLoading',
headerMode: 'none',
lazy: true,
defaultNavigationOptions: {
gesturesEnabled: false,
},
}
)
export default createAppContainer(MainStack)
App.js
import React, { Component } from 'react'
import {
View,
Text,
} from 'react-native'
import { inject, observer } from 'mobx-react/native'
import style from './style'
import AppStack from '../../routes/AppStack';
#inject('UserStore')
#observer
class App extends Component {
constructor(props) {
super(props)
this.state = {
}
}
componentDidMount() {
}
render() {
const { container } = style;
return (
<View style={container}>
<AppStack/>
</View>
)
}
}
export default App
AppStack
import React from 'react'
import { Easing, Animated } from 'react-native'
import { createAppContainer, createStackNavigator, createSwitchNavigator } from 'react-navigation'
import { UserStore } from '../stores'
import { Playground, Welcome, Login, Register, ConfirmationCode, App, Search, SearchResult, AuthLoading, BusinessDetail, BusinessMap, MyFavouriteBusiness, MakeAppointment, EditUserProfile, TermsAndConditions } from '../screens'
import TabStack from './TabStack'
const transitionConfig = () => {
return {
transitionSpec: {
duration: 750,
easing: Easing.out(Easing.poly(4)),
timing: Animated.timing,
useNativeDriver: true,
},
screenInterpolator: sceneProps => {
const { layout, position, scene } = sceneProps
const thisSceneIndex = scene.index
const width = layout.initWidth
const translateX = position.interpolate({
inputRange: [thisSceneIndex - 1, thisSceneIndex],
outputRange: [width, 0],
})
return { transform: [{ translateX }] }
},
}
}
export default createStackNavigator(
{
TabStack,
SearchResult: {
screen: SearchResult
},
// SearchResult: SearchResult,
BusinessDetail: {
screen: BusinessDetail
},
BusinessMap: {
screen: BusinessMap
},
MakeAppointment: {
screen: MakeAppointment
},
TermsAndConditions: {
screen: TermsAndConditions
},
EditUserProfile: {
screen: EditUserProfile
}
},
{
initialRouteName: 'TabStack',
headerMode: 'none',
lazy: true,
}
)
TabStack
import React from 'react';
import { createBottomTabNavigator, createAppContainer } from 'react-navigation';
import {
Search,
UserProfile,
MyFavouriteBusiness,
MyAppointments
} from '../screens'
import Icon from 'react-native-vector-icons/Feather';
import Colors from '../utils/Colors'
export default TabStack = createBottomTabNavigator(
{
// Search: {
// screen: Search
// },
Search:Search,
MyFavouriteBusiness: MyFavouriteBusiness,
MyAppointments: MyAppointments,
UserProfile,
},
{
defaultNavigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, horizontal, tintColor }) => {
const { routeName } = navigation.state;
let icon_name;
switch (routeName) {
case 'Search': {
icon_name = 'search'
break;
}
case 'MyFavouriteBusiness': {
icon_name = 'heart'
break;
}
case 'MyAppointments': {
icon_name = 'calendar'
break;
}
case 'UserProfile': {
icon_name = 'user'
break;
}
default: {
icon_name = 'search'
break;
}
}
return <Icon name={icon_name} size={horizontal ? 20 : 25} color={tintColor} />;
},
}),
initialRouteName: 'Search',
tabBarOptions: {
activeTintColor: Colors.pink,
inactiveTintColor: Colors.black,
showLabel: false,
style: {
backgroundColor: 'white'
}
},
}
)
I tried to separate AppStack to another file and then import it in screen 'App.js' and call the stack there and then I get this issue.
in addition, I'm tried to understand what to difference between
declare navigation this way
export default TabStack = createBottomTabNavigator(
{
Search:Search,
MyFavouriteBusiness: MyFavouriteBusiness,
MyAppointments: MyAppointments,
UserProfile,
},
to this way
export default TabStack = createBottomTabNavigator(
{
Search:{
screen:Search,
}
},
what the declaration of 'screen:'Search'' do? when to use this way and when the other way?
I had the same issue today. It seems that in my case the problem was a wrong import of a screen declared in the StackNavigator.
Cheers! Nicu

Navigation using 'react-native-navigation'

I have created app using 'react-native-navigation' and first navigation working fine.
Navigation.startSingleScreenApp({
screen: {
screen: 'drawer.HomeScreen',
title: '',
navigatorStyle: {
navBarHidden: true
}
}
});
I got issue in navigation
import { Navigation } from 'react-native-navigation';
and tried to navigate using
Navigation.push({
component: {
name: 'drawer.DashboardScreen'
}
});
startMainTab.js
const startTabs = () => {
Promise.all([
Icon.getImageSource("ios-share-alt", 30),
Icon.getImageSource("ios-menu", 30)
]).then(sources => {
Navigation.startTabBasedApp({
tabs: [{
screen: 'drawer.AnalyticsScreen',
navigatorButtons: {
leftButtons: [{
icon: sources[1],
title: "Menu",
id: 'sideDrawerToggle'
}]
}
},
{
screen: 'drawer.DashboardScreen',
navigatorButtons: {
leftButtons: [{
icon: sources[1],
title: "Menu",
id: 'sideDrawerToggle'
}]
}
}
],
drawer: {
left: {
screen: 'drawer.SideDrawer'
}
}
});
});
}
SideDrawer.js
export default startTabs;
export default class SideDrawer extends Component {
constructor(props) {
super(props);
this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent);
}
componentWillMount() {
this.props.navigator.setOnNavigatorEvent(this.onNavigationEvent)
}
onNavigationEvent = (event) => {
// handle a deep link
if (event.type == 'DeepLink') {
const parts = event.link;
alert("Scree: " + parts)
//this.navigateToAbout()
this.props.navigator.push({
screen: "drawer.HomeScreen"
})
if (parts == 'drawer.DashboardScreen') {
//this.onPressScreen1();
}
}
}
navigateToAbout = () => {
this.props.navigator.push({
screen: 'drawer.DashboardScreen'
})
}
render() {
return ( <
View style = {
styles.container
} >
<
Text > SideDrawer < /Text> <
TouchableHighlight onPress = {
this.navigateToAbout.bind(this)
} >
<
Text > Click Me < /Text> <
/TouchableHighlight> <
/View>
)
}
}
Since pushing a screen is an action you perform on an existing navigation stack, you need to call it on your current component navigator object which you'll automagically get as a prop:
this.props.navigator.push({screen: 'drawer.DashboardScreen'})
I strongly suggest you migrate to react-native-navigation v2 as v1 has limited functionality and is no longer maintained.
Download source code from here(React Native Navigation)
App.js:
import React, {Component} from 'react';
import {createStackNavigator,createAppContainer} from 'react-navigation'
import HomeScreen from './Screens/HomeScreen';
import ProfileScreen from './Screens/ProfileScreen';
import ContactScreen from './Screens/ContactScreen';
import MainScreen from './Screens/MainScreen'
export default class App extends Component {
render() {
return <AppNavigationContainer/>
}
}
const AppNavigator = createStackNavigator({
Main:MainScreen,
Home: HomeScreen,
Profile: ProfileScreen,
Contact:ContactScreen
}, {
initialRouteName: 'Main',
navigationOptions: {
headerTitleStyle: {
fontWeight: "bold",
color: "red",
},
headerTintColor: "red"
}
})
const AppNavigationContainer = createAppContainer(AppNavigator);
MOVE FROM ONE SCREEN TO ANOTHER:
this.props.navigation.navigate('Profile')
Thanks!

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