React native react-navigation drawer not opening - react-native

I am using react-navigation as the navigation package for my react native application. and have also installed and configured react-native-gesture-handler along with react-navigation as mentioned in the documentation.
The problem i am facing is that the drawer doesn't open at random times. mostly this occurs when user goes through along the main stack navigation and comes back to home to open the drawer. otherwise the drawer seems to be working without any issues.
this is how i have configured my navigation,
MAIN STACK NAVIGATION
const AppStack = createStackNavigator(
{
DrawerNav: DrawerNav,
Home: Home,
Notification: Notification,
HomeSearch: HomeSearch
}
DRAWER NAVIGATION
const MyDrawerNavigator = createDrawerNavigator(
{
Home: Home,
MyAccount: MyAccount,
ContactUs: ContactUs,
InviteFriend: InviteFriend,
Terms: Terms,
SignOut: SignOut
},
And the MAIN STACK also contains a few TAB STACK also,
I want to know why the drawer doesn't respond.
The Code i used to open the drawer was
this.props.navigation.openDrawer();
bu the above code gave
this.props.navigation.openDrawer() undefined
when ever the above crash i mentioned occurs
as a fix i used,
import { DrawerActions } from "react-navigation";
this.props.navigation.dispatch(DrawerActions.openDrawer())
the above code also stop working after a the user goes through the STACK navigation a few times, but doesn't give any errors on development.
This error occurs both on production as well as development
currently running
react native : 0.59.8
react : 16.8.3
react navigation: 3.9.1,
react-native-gesture-handler:1.1.0,
any help would be much appreciated,
Thanks in advance

Try wrapping all your stack navigation with Drawer navigation.
const StackNav = createStackNavigator({
Home: Home,
Notification: Notification,
HomeSearch: HomeSearch
}
Now wrap the above with Drawer navigation
const AppStack = createDrawerNavigator({
StackNav: {
screen: StackNav,
navigationOptions: {
drawerLabel: <Hidden />,
},
},
Home: Home,
MyAccount: MyAccount,
ContactUs: ContactUs,
InviteFriend: InviteFriend,
Terms: Terms,
SignOut: SignOut
});
Now the StackNav will be showing in the Drawer as one of the screens. So create a class and return null then pass it down to Drawer label.
class Hidden extends Component {
render() {
return null;
}
}
Now you'll be able to call the this.props.navigation.openDrawer(); anywhere on the app. Let me know if it works.

I think you can use another easy way to handle this problem :
You can use react-native-drawer that is available in this link now i'm going to show you how you can work with it :
AppStack :
const AppStack = createStackNavigator(
{
Home: Home,
Notification: Notification,
HomeSearch: HomeSearch
}
Home Navigation
const MyHomeNavigator = createStackNavigator(
{
Home: Home,
MyAccount: MyAccount,
ContactUs: ContactUs,
InviteFriend: InviteFriend,
Terms: Terms,
SignOut: SignOut
},
Now lets assume this is your HomePage :
HomePage
import Drawer from 'react-native-drawer'
import DrawerComponent from '../components/drawer'
export default class HomePage extends Component{
render() {
return (
<Drawer ref={(ref) => this._drawer = ref} content={<DrawerComponent {...this.props}/>} side='right' captureGestures openDrawerOffset={0.3} acceptTap>
//your home page components
</Drawer>
)
}
}
as you can see you can access to the drawer by this._drawer and here i will show you how does <DrawerComponent> like :
DrawerComponent :
export default class DrawerComponent extends React.Component {
navigateTo = (path) => {
this.props.navigation.navigate(path)
}
render(){
return(
<View>
<View>
<Item path='MyAccount' navigate = {this.navigateTo}/>
<Item path='ContactUs' navigate = {this.navigateTo}/>
<Item path='InviteFriend' navigate = {this.navigateTo}/>
//And you add all the item you need here with navigateTo function
</View>
<View>
//LogOut Section
</View>
</View>
)
}
}
This Works for me fine, I hope this works for you too.
Best regards .

Related

react-native expo deep linking -how to get a shareable link of my app

Functional Requirement: As a user 1, I want to share the link of a my profile screen to anyone by whatsapp/sms/email so that when he clicks that link, he will navigate to my app's user profile screen.
In the app, my profile has a button "Share"
When I click "Share" button, I want the URL to be the link of the my profile screen.
Question:
How to get the URL from deep linking and pass it in Share function?
Technical requirement: From the documentation in expo and other similar question in stack overflow, my understanding is that I can achieve it by using deep linking functionality.
However I am still not clear how to do it.
Environment:
React native app using Expo
A.Content of App.js
A-1 Screen navigation: Search profile screen-->Search result screen-->Profiledetails screen
const Searchafterloginstack = createStackNavigator({
SearchhomePostlogin: { screen: SearchhomePostlogin },
SearchresultPostlogin: { screen: SearchresultPostlogin },
Profiledetails: { screen: Profiledetails },
});
A-2. Bottom navigator
const AppNavigator = createBottomTabNavigator({
Login: {screen: Loginstack},
});
A-3. Another Bottom navigator
const PostloginNavigator = createBottomTabNavigator({
Home: {screen: PostloginFeed},
Find: {screen: Searchafterloginstack}
});
A-4. Appcontainer
const AppContainer = createAppContainer(createSwitchNavigator(
{ Prelogin: AppNavigator,
Postlogin: PostloginNavigator,
},
{initialRouteName: 'AppNavigator'}
));
export default class App extends React.Component {
render() {
return <AppContainer />
}
};
=============================================
B. Profiledetails.js (Profiledetails screen with "Share" button)
Screen navigation: Search profile screen-->Search result screen-->Profiledetails screen
export default class Profiledetails extends React.Component {
onShareMessage= ()=> {
Share.share({
url: Need help to get from deep linking-to navigate to profiledetails screen,
})
}
render() {
return (
<View >
<Text > {this.state.Name} </Text>
<Button title="Share" onPress={this.onShareMessage}/>
</View>
)}
}

How to add transition while navigating from one screen to other screen using react-navigation

I am using react-navigation to navigate from one screen to another screen. But while navigating I can see the navigation not good enough. So I am trying to add the transition while navigating from a screen to another screen. Any solution for this using react-navigation
if you want to just use react-navigation then use the following link
you will have to use Transitioner
class MyNavView extends Component {
...
render() {
return (
<Transitioner
configureTransition={this._configureTransition}
navigation={this.props.navigation}
render={this._render}
onTransitionStart={this.onTransitionStart}
onTransitionEnd={this.onTransitionEnd}
/>
);
}
or
You can use the following third party library for the Transition in navigation
Click Here
import { createStackNavigator } from 'react-navigation';
import { fromLeft } from 'react-navigation-transitions';
const appStack = createStackNavigator(
{
ScreenA: {
screen: ScreenA,
},
ScreenB: {
screen: ScreenB,
},
},
{
initialRouteName: 'ScreenA',
transitionConfig: () => fromLeft(),
},
);

Unmount or re-render screen in drawer navigator

I just added drawer navigator recently and wrapped my screens in createDrawerNavigator()
These are my current routes:
Home.js
Post.js
Settings.js
When a user navigates from Home to Post I pass a param that has the post data.
onPress={() => this.props.navigation.navigate('Post', {postData: postData})}
When ever the user goes back to Home from Post, then post will be unmounted. and mounted back again with fresh data when another post is clicked.
My issue is that with implementing the drawer, the Post screen does not get unmounted when navigating back to home, I keep gettings the same props and screen of the first post opened, over and over again.
This is my route setup:
import React from "react";
import { createDrawerNavigator, createStackNavigator, createAppContainer } from 'react-navigation';
import Home from './screens/Home';
import Post from './screens/Post';
import Settings from './screens/Settings';
import SideBar from './screens/sidebar';
const Drawer = createDrawerNavigator(
{
Home: {screen: Home},
Post: {screen: Post},
Settings: {screen: Settings}
},
{
initialRouteName: "Home",
backBehavior: 'initialRoute',
contentOptions: {
activeTintColor: "#e91e63"
},
contentComponent: props => <SideBar {...props} />,
}
);
const AppNavigator = createStackNavigator(
{
Drawer: {screen: Drawer},
},
{
initialRouteName: "Drawer",
headerMode: "none",
}
);
export default createAppContainer(AppNavigator);
What am I doing wrong?
I want each post screen to open and re render as new when navigating to it from Home.
For those using react-navigation v5. I faced the same issue my component was not unmounting by using goBack() for a screen link in drawer. After little research I found our that in latest version of react-navigation they have added an attribute unmountonblur in screen options for drawer navigator by default its false that's why component doesn't unmount. I am using this to solve my problem.
Here is my code
<Drawer.Screen name="ResetLogsStack" component={ResetLogsStack} options={{unmountOnBlur:true}}/>
Here is the link for that: unmountonblur
I use to face the same issue. I made my screen Post listen to navigation focus event triggered by react-nativation here instead of componentDidMount.
import React from 'react';
import { View } from 'react-native';
import { NavigationEvents } from 'react-navigation';
const Post = () => (
<View>
<NavigationEvents
onWillFocus={payload => console.log('will focus',payload)}
onDidFocus={payload => console.log('did focus',payload)} //
onWillBlur={payload => console.log('will blur',payload)}
onDidBlur={payload => console.log('did blur',payload)}
/>
{/*
Your view code
*/}
</View>
);
With onDidFocus, you may get the navigation param, fetch data, and/or update state. You may clear screen state with onDidBlur if needed.
Alternatively, you can do imperative coding as this doc here
Update :
By the way, I am wondering why you put Post with Drawer? Is it just to have a link in the drawer that can access to the Post page?
In my opinion, you should move Home and Post to new stack and make Home as initial Route. This will make sure that the Post is unmounted after navigating back to Home.
Check out my sample below
const HomeStack = createStackNavigatior({
Home: {screen: Home},
Post: {screen: Post},
}, {
initialRouteName: 'Home',
...
})
const Drawer = createDrawerNavigator(
{
HomeStack
Settings: {screen: Settings}
},
{
initialRouteName: "HomeStack",
backBehavior: 'initialRoute',
contentOptions: {
activeTintColor: "#e91e63"
},
contentComponent: props => <SideBar {...props} />,
}
);
It's the way react-navigation works, to counter this you can add listeners, like so:
<NavigationEvents
onDidFocus={payload => { console.log(payload.state.params,'<- this has your new params') }}
/>
OR
this.props.navigation.addListener('didFocus', payload=>{console.log(payload)})
Check this for more information
I lost several hours on this after updating React Navigation from 2.14.2 to 3.11.0. The funny thing is that it was working perfectly and after upgrade pages were not re-rendering which was causing to wrong language and not actual data on the pages.
What I have found is the issue DrawerNavigator screen shouldn't unmount
So part of us complain why it is not rerendering screens and part was complaining why it was rerendering. The second part won the battle :)
Basically the solution was as expected: to listen to WillFocus event...
Just add this to code to your component if you want it to be rerendered on each visit.
/**
* When using React Navigation Component is not umnounted and instead stored in navigator.
* We need component to be rerendered during each visit to show right info and language
*/
componentDidMount() {
//this.props.navigation will come in every component which is in navigator
focusSubscription = this.props.navigation.addListener(
'willFocus',
payload => {
this.forceUpdate();//Native react function to force rerendering
}
);
this.setState({focusSubscription: focusSubscription});
}
componentWillUnmount() {
this.state.focusSubscription.remove();
}
I tried to use the method suggested in the answers but they didn't work perfectly with my case.
Solution:
I tried to flip createDrawerNavigator() with createStackNavigator() and it worked perfectly like before!
I don't have to use react navigation events, normal event like componentWillUnmount and componentWillMount work perfectly.
const MainScreens = createStackNavigator(
{
Home: {screen: Home},
Post: {screen: Post},
Settings: {screen: Settings}
},
{
initialRouteName: "Home",
headerMode: "none",
}
);
const AppNavigator = createDrawerNavigator(
{
Main: {screen: MainScreens},
},
{
initialRouteName: "Main",
backBehavior: 'initialRoute',
contentOptions: {
activeTintColor: "#e91e63"
},
contentComponent: props => <SideBar {...props} />,
}
);
export default createAppContainer(AppNavigator);
Not sure if there's anything wrong in what I did, but its working fine until now.
As per Muhammad Zain response, if you are using react navigation v5, you can pass directly to the Drawer screen the option unmountOnBlur
options={{unmountOnBlur:true}}
and that will be enough.
React navigation docs
I'm using react-navigation for months. But placing screens directly into Drawer navigator prevents willunmount method to be called. First place screen in a stack navigator then place it into drawer navigator.

How to implement Drawer and TabBar in StackNavigator

I always use react-native-router-flux for navigation, but on this project I need to use react-navigation and I got some troubles with it. I need to implement drawer and tabBar inside stack navigator.
Problems:
I use header component from native-base library but i can't open
drawer.
How to use my own customized component for drawer and tabBar?
Maybe I need to chage structure. I will consider any recommendations how to improve structure.
I used version 3 of react-navigation.
My code:
const AppStackNavigator = createStackNavigator({
loginFlow: {
screen: createStackNavigator({
intro: { screen: Intro },
login: { screen: Login },
registration: { screen: Registration },
}),
navigationOptions: {
header: null
}
},
mainFlow: {
screen: createStackNavigator({
MyDrawer: createDrawerNavigator({
Dashboard: {
screen: Home,
},
first: {
screen: first,
},
second: {
screen: second
},
third: {
screen: third
},
last: {
screen: last
}
}),
// settings: { screen: SettingsScreen },
someTab: {
screen: createBottomTabNavigator({
main: { screen: Home },
firsrTab: { screen: Screen1 },
secondTab: { screen: Screen2 },
thirdTab: { screen: Screen3 },
nextTab: { screen: Screen4 }
}),
navigationOptions: {
header: null
},
}
}),
navigationOptions: {
header: null
}
}
});
const AppContainer = createAppContainer(AppStackNavigator);
import React from 'react';
import { Header, Left, Icon, Right } from 'native-base';
const CustomHeader = (props) => {
return(
<Header>
<Left>
<Icon
name='menu'
onPress={() => {this.props.navigation.openDrawer()}}
/>
</Left>
</Header>
)
}
export { CustomHeader }
You might wanna consider the SwitchNavigator for the authentication flow instead of a Stack at the top as it replaces the routes so that you can never navigate back to the login/signup/splash once you get into the application and for accessing Tabs and Drawer inside stack/switch, you can wrap the Drawer inside your top level navigator and tab inside the drawer.
So you root navigation would look like this.
export default RootNavigation = createSwitchNavigator({
LoginScreen: {screen: LoginContainer},
Application: {screen: AppDrawer},
});
Your drawer navigator should be like the following:
const AppDrawer = createDrawerNavigator({
ApplicationTab: {screen: TabBar},
... other screen that you might want to use in drawer navigation.
}, {
contentComponent : (props) => <MyCustomDrawer {...props} />
});
and, Tab Navigator would be,
const TabBar = createBottomTabNavigator({
TabScreen1: {screen: Tab1},
... other tabs...
}, {
tabBarComponent : (props) => <MyTabBar {...props} />
});
If you put each of those navigators in single file then please do declare Tab before Drawer and Drawer before the Switch, else it would give errors.
In my experience, customising drawer navigator is very simple and fruitful but customising tab is not, there aren't proper API doc for the same and community answers are also somewhat misleading.
BUT, with normal use cases and for most of the vivid ones too, you can do your job without needing to override the default one as it is already highly operable and customisable in terms of icons, materialism and each tab exposes its on onPress that can also be easily overriden.
and as you as the drawer is not getting operated from/via the header, then can you please ensure that the navigation prop you are using to operate the drawer open close or toggle action is the one given by drawer ?

How to use goBack in react-native to goBack two screens one by one

I have 4 screens in my react application and i have used push method to go to each screen. When i go from A-->B-->C and press goBack on C it comes back to B. But when i press goBack on B it remains in the same screen. Is there a solution for this?
I think it would be better if you use stack navigator of react-navigation and keep your screen in that like below:
const AppNavigator = createStackNavigator(
{
Home: {
screen: HomeScreen, // <----
},
Details: {
screen: DetailsScreen, // <----
},
},
{
initialRouteName: 'Home',
}
);
export default App extends React.Component {
render() {
/* In the root component we are rendering the app navigator */
return <AppNavigator />;
}
}