React Native render() not being called after navigation - react-native

I have a Footer component which is shared to all my screens. It has a method that updates the current property and returns to Home Page
...
class FooterComp extends Component {
changeProperty = async (data) => {
await AsyncStorage.setItem('CurrentPropertyID', data.toString());
await this.setState({ CurrentPropertyID: data.toString() });
NavigationService.navigate('Home');
}
}
...
My navigation service:
import { NavigationActions } from 'react-navigation';
let _navigator;
function setTopLevelNavigator(navigatorRef) {
_navigator = navigatorRef;
}
function navigate(routeName, params) {
_navigator.dispatch(
NavigationActions.navigate({
routeName,
params,
})
);
}
// add other navigation functions that you need and export them
export default {
navigate,
setTopLevelNavigator,
};
My App.js
class App extends Component {
render() {
const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
return (
<Provider store={store}>
<AppContainer
ref={navigatorRef => {
NavigationService.setTopLevelNavigator(navigatorRef);
}}
/>
</Provider>
);
}
}
export default App;
const MainStackNavigator = createStackNavigator({
Home: {
screen: HomeScreen,
navigationOptions: {
headerTitle: 'iRent'
}
},
Company: {
screen: CompanyDetails,
navigationOptions: {
headerTitle: 'Company Details'
}
},
Tenants: {
screen: Tenants,
navigationOptions: {
headerTitle: 'Tenants'
}
},
WorkOrders: {
screen: WorkOrders,
navigationOptions: {
headerTitle: 'Work Orders'
}
},
Applicants: {
screen: Applicants,
navigationOptions: {
headerTitle: 'Applicants'
}
},
Bills: {
screen: Bills,
navigationOptions: {
headerTitle: 'Bills'
}
}
}, {
defaultNavigationOptions: ({ navigation }) => {
return {
headerLeft: (
<Ionicons
style={{ paddingLeft: 10 }}
onPress={() => navigation.openDrawer()}
name="md-menu"
size={30}
/>
)
};
}
});
const AppDrawerNavigator = createDrawerNavigator({
iRent: {
screen: MainStackNavigator
},
Home: {
screen: HomeScreen,
navigationOptions: {
drawerIcon: <FontAwesome name="home" size={20} />
}
},
Company: {
screen: CompanyDetails,
navigationOptions: {
drawerIcon: <FontAwesome name="building-o" size={20} />
}
},
Tenants: {
screen: TenantDetails,
navigationOptions: {
drawerIcon: <Ionicons name="ios-person" size={20} />
}
},
Applicants: {
screen: Applicants,
navigationOptions: {
drawerIcon: <MaterialCommunityIcons name="account-search" size={20} />
}
},
WorkOrders: {
screen: WorkOrders,
navigationOptions: {
title: 'Work Orders',
drawerIcon: <Octicons name="checklist" size={20} />
}
},
Bills: {
screen: Bills,
navigationOptions: {
title: 'Bills',
drawerIcon: <Entypo name="text-document" size={20} />
}
},
LogOut: {
screen: Login,
navigationOptions: {
title: 'Log Out',
drawerIcon: <Entypo name="log-out" size={20} />
}
}
});
const AppSwitchNavigator = createSwitchNavigator({
Login: { screen: Login },
ForgotPassword: { screen: ForgotPassword },
Main: { screen: AppDrawerNavigator },
TenantDetails: { screen: TenantDetails },
EditData: { screen: EditData },
EditReview: { screen: EditReview },
ApplicantDetails: { screen: ApplicantDetails },
RunScreening: { screen: RunScreening },
OpenBGReport: { screen: OpenBGReport },
WorkOrderDetails: { screen: WorkOrderDetails },
ConvertToTenant: { screen: ConvertToTenant },
EditBill: { screen: EditBill },
NoAccess: { screen: NoAccess },
});
const AppContainer = createAppContainer(AppSwitchNavigator);
My HomeScreen
class HomeScreen extends Component {
constructor(props) {
super(props);
this.state = {
data: [
{ id: 1, title: 'Tenants', nav: 'Tenants', image: 'http://myirent.com/rent/appImg/tenants.jpg' },
{ id: 2, title: 'Applicants', nav: 'Applicants', image: 'http://myirent.com/rent/appImg/applicants.png' },
{ id: 3, title: 'Work Orders', nav: 'WorkOrders', image: 'http://myirent.com/rent/appImg/workOrders.png' },
{ id: 4, title: 'Bills', nav: 'Bills', image: 'http://myirent.com/rent/appImg/bills.png' }
],
currentPropertyID: null
};
}
componentDidMount = async () => {
await AsyncStorage.getItem('CurrentPropertyID')
.then((value) => {
const propID = JSON.parse(value);
this.setState({
currentPropertyID: propID.toString()
});
});
}
render() {
console.log('Render Main. PID: ' + this.state.currentPropertyID);
return (
<View style={styles.container}>
<FlatList
style={styles.list}
data={this.state.data}
keyExtractor={(item) => {
return item.id.toString();
}}
ItemSeparatorComponent={() => {
return (
<View style={styles.separator} />
);
}}
renderItem={(post) => {
const item = post.item;
return (
<TouchableOpacity
onPress={() => { this.props.navigation.navigate(item.nav); }}
>
<View style={styles.card}>
<Image style={styles.cardImage} source={{ uri: item.image }} />
<View style={styles.cardContent}>
<View>
<Text style={styles.title}>{item.title}</Text>
</View>
</View>
</View>
</TouchableOpacity>
);
}}
/>
<FooterComp />
</View>
);
}
}
The odd things is that after The FooterComp navigate to 'Home', the console.log() inside the render() method of HomeScreen component is not called. Shouldn't it be rendered after navigate to the component? I need to call the render() method to update screen.

Is not being called because the component hasn't been updated. I mean, with react-navigation the screens doesn't get unmounted, they just get blurred.
There is a component in react-navigation that will help you to solve this, just wrap your view with:
<View>
<NavigationEvents
onDidFocus={payload => console.log('Render Main. PID: ' + this.state.currentPropertyID)}
/>
{/*
Your view code
*/}
</View>

Related

React native disable StackNavigator and DrawerNavigator

I'm trying to disable some of the menus of my app according to the user access level.
Here are my Navigators:
const MainStackNavigator = createStackNavigator({
Home,
Company: {
screen: CompanyDetails,
navigationOptions: {
headerTitle: 'Company Details'
}
},
Tenants: {
screen: Tenants,
navigationOptions: {
headerTitle: 'Tenants'
}
}
}, {
defaultNavigationOptions: ({ navigation }) => {
return {
headerLeft: (
<Ionicons
style={{ paddingLeft: 10 }}
onPress={() => navigation.openDrawer()}
name="md-menu"
size={30}
/>
)
};
}
});
const AppDrawerNavigator = createDrawerNavigator({
myApp: {
screen: MainStackNavigator
},
Home: {
screen: Home,
navigationOptions: {
drawerIcon: <FontAwesome name="home" size={20} />
}
},
Company: {
screen: CompanyDetails,
navigationOptions: {
drawerIcon: <FontAwesome name="building-o" size={20} />
}
},
Tenants: {
screen: TenantDetails,
navigationOptions: {
drawerIcon: <Ionicons name="ios-person" size={20} />
}
},
LogOut: {
screen: Login,
navigationOptions: {
title: 'Log Out',
drawerIcon: <Entypo name="log-out" size={20} />
}
}
});
I would like to disable the Company menu (showing but no clickable) if the userAccessLevel is not 1. I can get the userAccessLevel from my authentication: AsyncStorage.getItem('UserLevel')
Is it possible?
Thanks
It's possible, You can use customdrawernaivgation.
const AppDrawerNavigator = createDrawerNavigator({
myApp: {
screen: MainStackNavigator
},
Home: {
screen: Home,
navigationOptions: {
drawerIcon: <FontAwesome name="home" size={20} />
}
},
Company: {
screen: CompanyDetails,
navigationOptions: {
drawerIcon: <FontAwesome name="building-o" size={20} />
}
},
Tenants: {
screen: TenantDetails,
navigationOptions: {
drawerIcon: <Ionicons name="ios-person" size={20} />
}
},
LogOut: {
screen: Login,
navigationOptions: {
title: 'Log Out',
drawerIcon: <Entypo name="log-out" size={20} />
}
}
}, {
drawerPosition: 'left',
drawerType: 'slide',
contentComponent: CustomDrawerNavigation,
drawerBackgroundColor: '#091b40',
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
drawerWidth: (width / 3) * 2,
});
class CustomDrawerNavigation extends React.Component {
render() {
return (
<SafeAreaView>
<ScrollView>
{data.map((each, index) => {
if(each.name === 'Company' && level !== 1) {
return <View/>;
}
return (
<TouchableOpacity
key={each.name}
onPress={() => this.props.navigation.navigate(each.route)}>
<View style={styles.menuContainer}>
<Icon style={styles.iconStyle} name={each.icon} />
<Text style={styles.textStyle}>{translate(each.name)}</Text>
</View>
</TouchableOpacity>
);
});
}
)};
}
Hope this will help you

Drawer does not open on first touch

I have a header that should open a drawer once it is touched. However the current behaviour is that it shows immediately the Profile screen (the drawer does not open) on first touch. If you touch the header again then the drawer is actually shown.
import ...
const navigationOptions = (navigation) => {
return {
title: navigation.screenProps.t('app.title')
}
}
const defaultNavigationOptionsWithHeader = ({ navigation }) => {
return {
headerStyle: {
backgroundColor: Colors.backgroundColor,
},
headerTintColor: Colors.main,
headerTitleStyle: {
fontWeight: 'bold'
},
headerRight: <TouchableOpacity style={{ marginRight: 10 }} onPress={() => navigation.dispatch(DrawerActions.openDrawer())}>
<Ionicons
name={Platform.OS === 'ios'
? 'ios-menu'
: 'md-menu'}
size={40}
color={Colors.main}
/>
</TouchableOpacity>
}
}
const defaultNavigationOptionsWithoutHeader = ({ navigation }) => {
return {
headerStyle: {
backgroundColor: Colors.backgroundColor,
},
headerTintColor: Colors.main,
headerTitleStyle: {
fontWeight: 'bold'
}
}
}
const AuthStack = createStackNavigator(
{
Login: {
screen: LoginScreen,
navigationOptions: navigationOptions
},
Registration: {
screen: RegistrationScreen,
navigationOptions: navigationOptions
}
}, {
initialRouteName: 'Login',
defaultNavigationOptions: defaultNavigationOptionsWithoutHeader
});
const TabStack = createStackNavigator(
{
App: {
screen: TabNavigator,
navigationOptions: navigationOptions
}
}, {
defaultNavigationOptions: defaultNavigationOptionsWithHeader
}
);
const MenuStack = createStackNavigator(
{
App: {
screen: MenuNavigator,
navigationOptions: navigationOptions
}
}, {
defaultNavigationOptions: defaultNavigationOptionsWithHeader
}
);
const appNavigationOptions = (navigation) => {
return {
initialRouteName: 'Tab'
}
}
const AppStack = createSwitchNavigator(
{
Tab: TabStack,
Menu: MenuStack
},
{
defaultNavigationOptions: appNavigationOptions
}
)
export default createAppContainer(createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
Auth: AuthStack,
App: AppStack
},
{
initialRouteName: 'AuthLoading',
}
));
Does anybody know what causes this issue? The menu navigator is defined as follows:
import ...
handleHome = (navigation) => {
navigation.navigate('App')
}
handleLogout = (navigation) => {
logout();
navigation.navigate('Auth')
}
const config = Platform.select({
web: { headerMode: 'screen' },
default: {},
});
const navigationOptions = (navigation) => {
return {
header: null
}
}
const ProfileStack = createStackNavigator(
{
Map: {
screen: ProfileScreen,
navigationOptions: navigationOptions
}
},
config
);
ProfileStack.navigationOptions = (navigation) => {
return {
drawerLabel: navigation.screenProps.t('loggedin.sidebar.profile'),
drawerIcon: ({ focused }) => (<DrawerIcon
focused={focused}
name={
Platform.OS === 'ios'
? `ios-contact'}`
: 'md-contact'
}
/>)
};
}
ProfileStack.path = '';
const PreferencesStack = createStackNavigator(
{
Settings: {
screen: PreferencesScreen,
navigationOptions: navigationOptions
}
},
config
);
PreferencesStack.navigationOptions = (navigation) => {
return {
drawerLabel: navigation.screenProps.t('loggedin.sidebar.preferences'),
drawerIcon: ({ focused }) => (<DrawerIcon
focused={focused}
name={
Platform.OS === 'ios'
? `ios-settings'}`
: 'md-settings'
}
/>)
}
};
const LogoutStack = createStackNavigator(
{
Logout: {
screen: () => null,
navigationOptions: navigationOptions
}
},
config
);
LogoutStack.navigationOptions = (navigation) => {
return {
drawerLabel: navigation.screenProps.t('button.logout'),
drawerIcon: ({ focused }) => createDrawerIcon('log-out', focused)
};
}
const TabStack = createStackNavigator(
{
Logout: {
screen: () => null,
navigationOptions: navigationOptions
}
},
config
);
TabStack.navigationOptions = (navigation) => {
return {
drawerLabel: navigation.screenProps.t('app.title'),
drawerIcon: ({ focused }) => createDrawerIcon('home', focused)
};
}
createDrawerIcon = (icon, focused = false) => {
return <DrawerIcon
focused={focused}
name={
Platform.OS === 'ios'
? 'ios-' + icon
: 'md-' + icon
}
/>
}
const MenuDrawerItem = (props) => {
return <TouchableOpacity onPress={props.onPress} >
<View style={styles.item}>
<View style={styles.iconContainer}>
{createDrawerIcon(props.icon)}
</View>
<Text style={styles.label}>{props.text}</Text>
</View>
</TouchableOpacity >
}
const MenuDrawer = (props) => (
<ScrollView contentContainerStyle={{ flex: 1, flexDirection: 'column', justifyContent: 'space-between' }}>
<SafeAreaView forceInset={{ top: 'always', horizontal: 'never' }}>
<MenuDrawerItem onPress={() => this.handleHome(props.navigation)} text={props.screenProps.t('app.title')} icon={'home'} />
<DrawerItems {...props} />
</SafeAreaView>
<MenuDrawerItem onPress={() => this.handleLogout(props.navigation)} text={props.screenProps.t('button.logout')} icon={'log-out'} />
</ScrollView>
);
const menuNavigator = createDrawerNavigator({
ProfileStack,
PreferencesStack
}, {
drawerPosition: 'right',
contentComponent: props => <MenuDrawer {...props} />,
contentOptions: {
activeTintColor: Colors.main
},
initialRouteName: 'ProfileStack'
}
);
menuNavigator.path = ''
export default menuNavigator
const styles = ...
That's probably you might have something other in focus.
May be Keyboard, TextField, Or some other things which are in focus and when you click for the first time the focus gets removed and when you press for the second time the drawer gets opened.
Try calling an alert instead of opening the drawer on button press and then debug that. That will troubleshoot the issue

icon in component header is not showing

I am following the doc example here to add a plus + to component header:
import React, { Component} from 'react';
import { SectionList, View, Image, StyleSheet, Text, TouchableOpacity, Platform, TouchableHighlight, AppRegistry } from 'react-native';
import {Icon } from "react-native-elements";
export default class Event extends React.Component {
static navigationOptions = ({navigation}) => {
console.log("in event header");
return {
headerTitle: 'Event',
headerRight: (
<TouchableOpacity>
<Icon
name="plus"
size={30}
type='octicon'
onPress={navigation.getParam('navToNewEvent')}
/>
</TouchableOpacity>
),
};
}
_navToNewEvent = () => {
console.log("Route to new event");
this.props.navigation.navigate("NewEvent");
};
async componentDidMount(){
this.props.navigation.setParams({ navToNewEvent: this._navToNewEvent })
....
}
However the plus + is not showing in component header:
What is missing in my code above?
UPDATE: the navigation code before component Event is:
return createBottomTabNavigator(
{
Event: {screen: EventStack},
Group: {screen: GroupStack},
Contact: {screen: ContactStack},
}, bottomTabNavOptions
);
const bottomTabNavOptions = {
defaultNavigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, tintColor }) => {
const { routeName } = navigation.state;
console.log("route name", routeName);
let iconName;
if (routeName === 'Event') {
iconName = `list-unordered`;
} else if (routeName === 'NewEvent') {
iconName = "kebab-horizontal";
} else if (routeName === 'NewUser') {
iconName = `person`;
} else if (routeName === 'ListUser') {
iconName = `organization`
}
return <Icon name={iconName} size={30} color={tintColor} type='octicon' />;
},
}),
tabBarOptions: {
activeTintColor: 'tomato',
inactiveTintColor: 'gray',
},
};
const EventStack = createStackNavigator({
Event: {
screen: EventWithSelf,
navigationOptions: {
title: 'Event',
},
},
NewEvent: {
screen: NeweventWithSelf,
navigationOptions: {
title: 'New Event',
},
},
EditEvent: {
screen: EditEventWithSelf,
navigationOptions: {
title: 'Edit Event',
},
},
Chat: {
screen: ChatWithSocket,
navigationOptions: {
title: 'Chat',
},
},
});
Simply looking at the code doesn't seem wrong. There is one catch. Would you like to modify this?
static navigationOptions = ({navigation}) => {
console.log("in event header");
return {
title: 'Event',
headerRight: (
<TouchableOpacity>
<Icon
name="plus"
size={30}
type='octicon'
onPress={() => navigation.getParam('navToNewEvent')}
/>
</TouchableOpacity>
),
};
}
You can use defaultNavigationOptions
The Event tab you represent is not a single screen. As a common header, configure the title and button in defaultNavigationOptions.
defaultNavigationOptions: ({ navigation }) => ({
...
headerTitle: 'Event',
headerRight: (
<TouchableOpacity>
<Icon
name="plus"
size={30}
type='octicon'
onPress={navigation.getParam('navToNewEvent')}
/>
</TouchableOpacity>
),

Remove the navigation header from the react-native screen - stack navigation

I have a screen which has tab-bar navigation where each screen is of type stack navigation with a couple of screens defined in each. When I navigate from FamilyMembers to SingleContact screen I don't want to see the navigation bar with the back button on top. I want my view (the blue one) in single contact to start from the top. But it appears although I set the header to null! Please help.
//------------------- Single Contact Screen----------//
import { Text, AsyncStorage, Image, FlatList, Alert, ActivityIndicator, Platform, StyleSheet, View } from 'react-native';
import { Icon, Container, Spinner, Content, Left, Right, Header, ListItem } from 'native-base'
import profileService from '../services/Api/ProfileService';
import { SafeAreaView } from 'react-navigation';
HEADER_MAX_HEIGHT = 100
HEADER_MIN_HEIGHT = 60
PROFILE_IMAGE_MAX_HEIGHT = 80
PROFILE_IMAGE_MIN_HEIGHT = 40
export default class SingleContact extends Component {
constructor(props) {
super(props);
this.state = { userName: "", contacts: [], userID: "", cookie: null, memberShips: [] };
}
async componentDidMount() {
}
onDataLoaded(result, userName) {
}
render() {
return (
<SafeAreaView>
<View style={{ flex: 1 }}>
//--------------------App.js navigation setup --------------------------//
const FamilyMembersStack = createStackNavigator({
FamilyMembers: {
screen: FamilyMembers,
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Family members",
}
}
},
SingleContact: {
screen: SingleContact,
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Contact"
}
}
},
}
, {
mode: 'modal',
headerMode: 'none'
});
const HomeScreenStack = createStackNavigator({
Home: {
screen: HomeScreen,
navigationOptions: ({ navigation }) => {
return {
header: null,
}
},
},
FamilyMembersStack: {
screen: FamilyMembersStack,
navigationOptions: ({ navigation }) => {
return {
header: null
}
}
},
AttendanceHistory: {
screen: AttendanceHistory,
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Attendance history"
}
}
},
OrderHistory: {
screen: OrderHistory,
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Order history"
}
}
}
});
HomeScreenStack.navigationOptions = {
tabBarLabel: 'My info',
tabBarIcon: ({ tintColor }) => (
<FaIcon name="user" size={20} color={tintColor} />
),
};
const ScheduleScreenStack = createStackNavigator({
Schedule: {
screen: ScheduleScreen,
navigationOptions: ({ navigation }) => {
return {
header: null,
}
},
}
});
ScheduleScreenStack.navigationOptions = {
tabBarLabel: 'Find a class',
tabBarIcon: ({ tintColor }) => (
<Icon name="md-calendar" size={20} color={tintColor} />
),
};
const ShopScreenStack = createStackNavigator({
Shop: {
screen: ShopScreen,
navigationOptions: ({ navigation }) => {
return {
header: null,
}
},
}
});
ShopScreenStack.navigationOptions = {
tabBarLabel: 'Get a pass',
tabBarIcon: ({ tintColor }) => (
<Icon name="md-basket" size={20} color={tintColor} />
),
};
const NotificationsScreenStack = createStackNavigator({
Notifications: {
screen: NotificationsScreen,
navigationOptions: ({ navigation }) => {
return {
header: null,
}
},
}
});
NotificationsScreenStack.navigationOptions = {
tabBarLabel: 'Notifications',
tabBarIcon: ({ tintColor }) => (
<Icon name="md-alert" size={20} color={tintColor} />
),
};
const EventsStack = createStackNavigator({
Events: {
screen: Events,
navigationOptions: ({ navigation }) => {
return {
tabBarLabel: "Events",
tabBarIcon: ({ tintColor }) => (
<Icon name="md-calendar" size={20} />
),
headerLeft: (
<Icon name="md-menu" style={{ paddingLeft: 10 }}
onPress={() => navigation.openDrawer()}
size={30} />
)
}
}
}
});
EventsStack.navigationOptions = {
tabBarLabel: 'Events',
tabBarIcon: ({ tintColor }) => (
<Icon name="md-calendar" size={20} color={tintColor} />
),
};
const DashboardTabNavigator = createBottomTabNavigator({
HomeScreenStack,
ScheduleScreenStack,
ShopScreenStack,
NotificationsScreenStack
},
{
navigationOptions: ({ navigation }) => {
const { routeName } = navigation.state.routes[navigation.state.index];
return {
header: null,
headerTitle: routeName,
}
},
tabBarOptions: {
activeTintColor: 'white',
inactiveTintColor: 'silver',
labelStyle: {
fontSize: 12,
},
style: {
backgroundColor: 'rgba(24,130,201,1);',
},
}
}, { initialRouteName: HomeScreenStack }
);
const DashboardStackNavigator = createStackNavigator({
DashboardTabNavigator: DashboardTabNavigator
});
const AppDrawerNavigator = createDrawerNavigator({
Dashboard: {
screen: DashboardStackNavigator
}
}, {
contentComponent: props => <DrawerContent {...props} />
});
const AppSwitchNavigator = createSwitchNavigator({
AuthLoading: AuthLoadingScreen,
Login: { screen: Login },
Dashboard: { screen: AppDrawerNavigator }
}, {
initialRouteName: 'AuthLoading',
}
);
const AppContainer = createAppContainer(AppSwitchNavigator);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
Did you already modify your FamilyMembersStack inside HomeScreenStack like this?
const HomeScreenStack = createStackNavigator({
Home: {
screen: HomeScreen,
navigationOptions: ({ navigation }) => {
return {
header: null,
}
},
},
// modify this Stack
FamilyMembersStack:{
screen: FamilyMembersStack,
navigationOptions: ({ navigation }) => {
return {
header: null
}
}
}
AttendanceHistory: {
screen: AttendanceHistory,
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Attendance history"
}
}
},
OrderHistory: {
screen: OrderHistory,
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Order history"
}
}
}
});
Follow up answer, remove the following. so that the header will render on the designated screen:
export default class SingleContact extends Component {
static navigationOptions = {
header: null, // remove this
}
constructor(props) {
super(props);
this.state = { userName: "", contacts: [], userID: "", cookie: null, memberShips: [] };
}
async componentDidMount() {
}
onDataLoaded(result, userName) {
}
render() {
//------------------------------//
const FamilyMembersStack = createStackNavigator({
FamilyMembers: {
screen: FamilyMembers,
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Family members",
header:null
}
}
},
SingleContact: {
screen: SingleContact,
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Contact",
header:null // and remove this
}
}
},
});

Deep Linking in Nested Navigators in react navigation

I am using react-navigation and as per the structure of my application, we have a tab navigator inside stack navigator, I am not been able to find any proper guide for implementing Deep-Linking.
https://v1.reactnavigation.org/docs/deep-linking.html. this doesn't give any reference for nested navigators.
You have to basically pass a path to every upper route untill you come to you nested route. This is indipendent of the type of navigator you use.
const HomeStack = createStackNavigator({
Article: {
screen: ArticleScreen,
path: 'article',
},
});
const SimpleApp = createAppContainer(createBottomTabNavigator({
Home: {
screen: HomeStack,
path: 'home',
},
}));
const prefix = Platform.OS == 'android' ? 'myapp://myapp/' : 'myapp://';
const MainApp = () => <SimpleApp uriPrefix={prefix} />;
In this case to route to an inner Navigator this is the route: myapp://home/article.
This example is using react-navigation#^3.0.0, but is easy to transfer to v1.
So, after the arrival of V3 of react navigation, things got extremely stable. Now i will present you a navigation structure with deep-linking in a Switch navigator -> drawerNavigator-> tabNavigator -> stack-> navigator. Please go step by step and understand the structure and keep referring to official documentation at everystep
With nested navigators people generally mean navigation structure which consists of drawer navigator, tab navigator and stackNavigator. In V3 we have SwitchNavigator too. So let's just get to the code,
//here we will have the basic React and react native imports which depends on what you want to render
import React, { Component } from "react";
import {
Platform,
StyleSheet,
Text,
View, Animated, Easing, Image,
Button,
TouchableOpacity, TextInput, SafeAreaView, FlatList, Vibration, ActivityIndicator, PermissionsAndroid, Linking
} from "react-native";
import { createSwitchNavigator, createAppContainer, createDrawerNavigator, createBottomTabNavigator, createStackNavigator } from "react-navigation";
export default class App extends Component<Props> {
constructor() {
super()
this.state = {
isLoading: true
}
}
render() {
return <AppContainer uriPrefix={prefix} />;
}
}
class WelcomeScreen extends Component {
state = {
fadeAnim: new Animated.Value(0.2), // Initial value for opacity: 0
}
componentDidMount() {
Animated.timing( // Animate over time
this.state.fadeAnim, // The animated value to drive
{
toValue: 1,
easing: Easing.back(), // Animate to opacity: 1 (opaque)
duration: 1000,
useNativeDriver: true // Make it take a while
}
).start(); // Starts the animation
}
render() {
let { fadeAnim } = this.state;
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center", backgroundColor: '#000' }}>
<Animated.View // Special animatable View
style={{ opacity: fadeAnim }}
>
<TouchableOpacity
onPress={() => this.props.navigation.navigate("Dashboard")}
style={{
backgroundColor: "orange",
alignItems: "center",
justifyContent: "center",
height: 30,
width: 100,
borderRadius: 10,
borderColor: "#ccc",
borderWidth: 2,
marginBottom: 10
}}
>
<Text>Login</Text>
</TouchableOpacity>
</Animated.View>
<Animated.View // Special animatable View
style={{ opacity: fadeAnim }}
>
<TouchableOpacity
onPress={() => alert("buttonPressed")}
style={{
backgroundColor: "orange",
alignItems: "center",
justifyContent: "center",
height: 30,
width: 100,
borderRadius: 10,
borderColor: "#ccc",
borderWidth: 2
}}
>
<Text> Sign Up</Text>
</TouchableOpacity>
</Animated.View>
</View>
);
}
}
class Feed extends Component {
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Button
onPress={() => this.props.navigation.navigate("DetailsScreen")}
title="Go to details"
/>
</View>
);
}
}
class Profile extends Component {
render() {
return (
<SafeAreaView style={{ flex: 1, }}>
//Somecode
</SafeAreaView>
);
}
}
class Settings extends Component {
render() {
return (
<View style={{ flex: 1 }}>
//Some code
</View>
);
}
}
const feedStack = createStackNavigator({
Feed: {
screen: Feed,
path: 'feed',
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Feed",
headerLeft: (
<Icon
style={{ paddingLeft: 10 }}
name="md-menu"
size={30}
onPress={() => navigation.openDrawer()}
/>
)
};
}
},
DetailsScreen: {
screen: Detail,
path: 'details',
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Details",
};
}
}
});
const profileStack = createStackNavigator({
Profile: {
screen: Profile,
path: 'profile',
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Profile",
headerMode: 'Float',
headerLeft: (
<Icon
style={{ paddingLeft: 10 }}
name="md-menu"
size={30}
onPress={() => navigation.openDrawer()}
/>
)
};
}
},
DetailsScreen: {
screen: Detail,
path: 'details',
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Details"
};
}
}
});
const settingStack = createStackNavigator({
Settings: {
screen: Settings,
path: 'settings',
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Settings",
headerLeft: (
<Icon
style={{ paddingLeft: 10 }}
name="md-menu"
size={30}
onPress={() => navigation.openDrawer()}
/>
)
};
}
},
DetailsScreen: {
screen: Detail,
path: 'details',
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Details"
};
},
}
});
const DashboardTabNavigator = createBottomTabNavigator(
{
feedStack: {
screen: feedStack,
path: 'feedStack',
navigationOptions: ({ navigation }) => {
let tabBarVisible = true;
if (navigation.state.index > 0) {
tabBarVisible = false;
}
return {
tabBarLabel: "Feed",
tabBarVisible,
//iconName :`ios-list${focused ? '' : '-outline'}`,
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-list" color={tintColor} size={25} />
)
};
}
},
profileStack: {
screen: profileStack,
path: 'profileStack',
navigationOptions: ({ navigation, focused }) => {
let tabBarVisible = true;
if (navigation.state.index > 0) {
tabBarVisible = false
}
return {
tabBarVisible,
tabBarLabel: "Profile",
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-man" color={tintColor} size={25} />
)
};
// focused:true,
}
},
settingStack: {
screen: settingStack,
path: 'settingsStack',
navigationOptions: ({ navigation }) => {
let tabBarVisible = true;
if (navigation.state.index > 0) {
tabBarVisible = false;
}
return {
tabBarVisible,
tabBarLabel: "Settings",
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-options" color={tintColor} size={25} />
)
}
}
},
},
{
navigationOptions: ({ navigation }) => {
const { routeName } = navigation.state.routes[navigation.state.index];
return {
// headerTitle: routeName,
header: null
};
},
tabBarOptions: {
//showLabel: true, // hide labels
activeTintColor: "orange", // active icon color
inactiveTintColor: "#586589" // inactive icon color
//activeBackgroundColor:'#32a1fe',
}
}
);
const DashboardStackNavigator = createStackNavigator(
{
DashboardTabNavigator: {
screen: DashboardTabNavigator,
path: 'dashboardtabs'
},
DetailsScreen: {
screen: Detail,
path: 'details',
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Details"
};
}
}
},
{
defaultNavigationOptions: ({ navigation }) => {
return {
headerLeft: (
<Icon
style={{ paddingLeft: 10 }}
name="md-menu"
size={30}
onPress={() => navigation.openDrawer()}
/>
)
};
}
}
);
const AppDrawerNavigator = createDrawerNavigator({
Dashboard: {
screen: DashboardStackNavigator,
path: 'welcome'
},
DetailsScreen: {
screen: Detail,
path: 'friends',
navigationOptions: ({ navigation }) => {
return {
headerTitle: "Details",
};
}
}
});
//Switch navigator , will be first to load
const AppSwitchNavigator = createSwitchNavigator({
Welcome: {
screen: WelcomeScreen,
},
Dashboard: {
screen: AppDrawerNavigator,
path: 'welcome'
}
});
const prefix = 'myapp://';
const AppContainer = createAppContainer(AppSwitchNavigator);
For the process to setup React-navigation deep-linking please follow the official documentation
DetailsScreen was in my different folder and that will have class component of your choice
To launch the App the deep-link URL is myapp://welcome
To go to root page the deep-link URL is myapp://welcome/welcome
(this will reach at first page of first tab of tab navigator)
To go to any particular screen of tab navigator (suppose details
screen in profile tab) -
myapp://welcome/welcome/profileStack/details
const config = {
Tabs: {
screens: {
UserProfile: {
path: 'share//user_share/:userId',
parse: {
userId: (userId) => `${userId}`,
},
},
},
},
};
const linking = {
prefixes: ['recreative://'],
config,
};
if you have a screen in tab navigator you can do it like this via react-navigation v5