React Navigation: A drawer with a stack and you want to hide the drawer on certain screens, but it doesn't hide - react-native

I'm facing the situation described in the docs, where I have a drawer with a stack and I want to hide the drawer on certain screens. Unfortunately the code below, influenced by the docs, does not work and the drawer can still be opened on pushed stack screens.
const MenuStack = createStackNavigator(
{
CheckedInMenu: { screen: MenuScreen },
CheckedIdMenuItemDetail: { screen: MenuItemDetailScreen }
},
{
navigationOptions: ({ navigation }) => {
let options = {
headerTitleStyle: {
color: headerColor
},
headerBackTitleStyle: {
color: headerColor
},
headerTintColor: headerColor
};
let drawerLockMode = "unlocked";
if (navigation.state.index > 0) {
drawerLockMode = "locked-closed";
}
return { ...options, drawerLockMode };
}
}
);
const checkedInDrawer = createDrawerNavigator(
{
MenuStack: {
screen: MenuStack,
navigationOptions: {
drawerLabel: SCREEN_TEXT_MENU_HEADER,
drawerIcon: ({ tintColor }) => (
<Image
source={require("../assets/icons/menu.png")}
resizeMode="contain"
style={{ width: 25, height: 25, tintColor: tintColor }}
/>
)
}
}
},
{
initialRouteName: "MenuStack",
drawerBackgroundColor: backgroundColor,
contentComponent: BurgerMenu,
contentOptions: {
activeTintColor: activeTintColor,
inactiveTintColor: headerColor,
activeBackgroundColor: backgroundColor,
itemStyle: { borderBottomWidth: 1, borderColor: borderColor },
labelStyle: { fontSize: 16, fontWeight: "500" }
}
}
);
What am I doing wrong?
Edit
Even if I console.log() the everything like this:
let options = {
headerTitleStyle: {
color: headerColor
},
headerBackTitleStyle: {
color: headerColor
},
headerTintColor: headerColor
};
let drawerLockMode = "unlocked";
console.log(navigation);
if (navigation.state.routeName !== "CheckedInMenu") {
drawerLockMode = "locked-closed";
}
if (navigation.state) console.log(navigation.state.routeName);
console.log({ ...options, drawerLockMode: drawerLockMode });
return { ...options, drawerLockMode: drawerLockMode };
It says on the CheckedInMenuItemDetailScreen that drawerLockMode = "locked-closed".
EDIT 2:
I now found out that the ONLY way to achieve this is exactly the way the docs say. You must do it like this:
MainStack.navigationOptions = ({ navigation }) => {
let drawerLockMode = "unlocked";
if (navigation.state.index > 0) {
drawerLockMode = "locked-closed";
}
return {
drawerLockMode
};
};
And you must try to do it within the navigationOptions of the definition of the stack, like I did in my original post above. Keep that in mind!

This code works. When navigate to DetailsScreen, the DrawerMenu is hidden. I have implemented it using your referenced the offical docs here.
import React, { Component } from 'react';
import { Platform, StyleSheet, TouchableHighlight, Text, View } from 'react-native';
import { createStackNavigator, createDrawerNavigator, createSwitchNavigator } from 'react-navigation';
class ProfileScreen extends Component {
render() {
return (
<View>
<Text> ProfileScreen </Text>
</View>
)
}
}
class DetailsScreen extends Component {
render() {
return (
<View>
<Text> DetailsScreen </Text>
</View>
)
}
}
class HomeScreen extends Component {
render() {
const { navigate } = this.props.navigation
return (
<View>
<Text> HomeScreen </Text>
<TouchableHighlight
onPress={() => navigate("Details", { screen: "DetailsScreen" })}
>
<Text>Screen One </Text>
</TouchableHighlight>
</View>
)
}
}
const FeedStack = createStackNavigator({
FeedHome: {
screen: HomeScreen,
navigationOptions: {
title: "test"
}
},
Details: DetailsScreen,
});
FeedStack.navigationOptions = ({ navigation }) => {
let drawerLockMode = 'unlocked';
if (navigation.state.index > 0) {
drawerLockMode = 'locked-closed';
}
return {
drawerLockMode,
};
};
const DrawerNavigator = createDrawerNavigator({
Home: FeedStack,
Profile: ProfileScreen,
});
const AppNavigator = createSwitchNavigator(
{
Drawer: DrawerNavigator,
}
);
export default class App extends Component {
render() {
return (
<View style={{ flex: 1 }} >
<AppNavigator />
</View>
);
}
}

Related

2 headers in screen in Dashboard navigator

I am new in ReactNative. I am learning things by just seeing examples.I get stuck in one issue. In my project i have implemented drawer navigation and tab navigator every thing is working fine but my screen shows 2 headers. I tried a lot to remove that header but still not get any success. In all child screen has its own header. I tried to remove child header(its happen) and modified parent header but not getting any success.
Here is my code :
import React, { Component } from 'react';
import BottomNavigation, { FullTab } from 'react-native-material-bottom-navigation';
import { View, StyleSheet, Keyboard, TouchableOpacity, Text } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import COLOR from '../Css/COLOR';
import { font_medium, font_regular, hidenavigation, getScreenWidth, getScreenHeight, printLogs } from '../Global/Utility';
import { AddDiamonds } from './AddDiamond';
import { DimondList } from './DiamondList';
import { DrawerNavigator } from 'react-navigation';
import { StackNavigator } from 'react-navigation';
import CustomSideMenu from './CustomSideMenu';
import { Dashboard } from './Dashboard';
const style = StyleSheet.create({
activeText: {
color: COLOR.action_bar,
fontFamily: font_medium
},
deactiveText: {
color: COLOR.tab_deselected_text_color,
fontFamily: font_regular
}
})
export class Home extends React.Component {
static navigationOptions = hidenavigation;
constructor(props) {
super(props);
}
apply_header = (val) => {
this.props.navigation.setParams({ Title: val });
}
goToNextTab = (tabName) => {
this.setState({ activeTab: tabName });
}
openDrawer() {
this.props.navigation.openDrawer();
}
tabs = [{
key: 'Dashboard',
icon: 'speedometer',
label: 'Dashboard',
pressColor: 'rgba(255, 255, 255, 0.16)'
},
{
key: 'Add Diamond',
icon: 'plus-circle-outline',
label: 'Add Diamond',
pressColor: 'rgba(255, 255, 255, 0.16)'
},
{
key: 'Diamond',
icon: 'diamond-stone',
label: 'Diamond',
pressColor: 'rgba(255, 255, 255, 0.16)'
}]
state = {
activeTab: 'Dashboard',
showFooter: true
};
renderIcon = icon => ({ isActive }) => (
<Icon size={24} color={isActive ? COLOR.action_bar : COLOR.tab_deselected_text_color} name={icon} />
)
renderTab = ({ tab, isActive }) => (
<FullTab isActive={isActive} key={tab.key} label={tab.label} labelStyle={isActive ? style.activeText : style.deactiveText} renderIcon={this.renderIcon(tab.icon)} />
)
render() {
const propsForChild = {
goToNextTab: (tabName) => this.goToNextTab(tabName),
openDrawer: () => this.openDrawer()
};
const propsForNav = {
nav: this.props,
openDrawer: () => this.openDrawer()
};
const addDimPropsForChild = {
openDrawer: () => this.openDrawer()
}
return (
<View style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
{
this.state.activeTab === 'Add Diamond' ? <Add_Dimond_Stack screenProps={addDimPropsForChild} /> : this.state.activeTab === 'Diamond' ? <Dimond_List_stack screenProps={propsForNav} /> : <Dashboard_Stack screenProps={propsForChild} />
}
</View>
{
this.state.showFooter ?
<BottomNavigation activeTab={this.state.activeTab} renderTab={this.renderTab} tabs={this.tabs} onTabPress={newTab => { this.setState({ activeTab: newTab.key }); }} />
: null
}
</View>
);
}
componentWillMount() {
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow.bind(this));
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide.bind(this));
}
componentWillUnmount() {
this.keyboardDidShowListener.remove();
this.keyboardDidHideListener.remove();
}
_keyboardDidShow() {
//alert('Keyboard Shown');
this.setState({ showFooter: false })
}
_keyboardDidHide() {
//alert('Keyboard Hidden');
this.setState({ showFooter: true })
}
}
export default MyDrawerNavigator = DrawerNavigator({
Page1: {
screen: props => <Home {...props} />,
}
},
{
contentComponent: props => (<CustomSideMenu {...props} />),
drawerWidth: (getScreenWidth() * 2.5) / 3,
}
);
const Dashboard_Stack = StackNavigator({
Dashboard_Stack: {
screen: Dashboard,
},
});
const Add_Dimond_Stack = StackNavigator({
Add_Dimond_Stack: {
screen: AddDiamonds,
},
});
const Dimond_List_stack = StackNavigator({
Dimond_List_stack: {
screen: DimondList,
},
});
Dashboard.js
export class Dashboard extends React.Component {
static navigationOptions = ({ navigation }) => {
const { state } = navigation;
return {
title: 'Dashboard',
headerStyle: styleApp.actionBarHeaderBgStyle,
headerTitleStyle: styleApp.actionBarTextStyle,
headerLeft:
<HeaderMenuIcon nav={state.params} />
}
}
Error is here
const Dashboard_Stack = StackNavigator({
Dashboard_Stack: {
screen: Dashboard,
},
});
Replace with
const Dashboard_Stack = StackNavigator({
Dashboard_Stack: {
screen: Dashboard,
navigationOptions:
{
header: null
},
},
});
If you are using different types of version than here are the answer for that
UPDATE as of version 5
As of version 5 it is the option headerShown in screenOptions
Example of usage:
<Stack.Navigator
screenOptions={{
headerShown: false
}}
>
<Stack.Screen name="route-name" component={ScreenComponent} />
</Stack.Navigator>
UPDATE
As of version 2.0.0-alpha.36 (2019-11-07),
there is a new navigationOption: headershown
navigationOptions: {
headerShown: false,
}
Old answer
I use this to hide the stack bar (notice this is the value of the second param):
{
headerMode: 'none',
navigationOptions: {
headerVisible: false,
}
}
I solved this issue by just added following line in my root App.js file
home: { screen: home,
navigationOptions:{
header:null
} }
I had a scenario where I am using v6 of react native navigation
import { createStackNavigator } from '#react-navigation/stack'
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs'
const BottomTabs = createBottomTabNavigator()
const TrackStack = createStackNavigator()
And I was getting 2 headers, the solution was deciding which header I wanted to show, the one from bottom tabs or from the stack navigator. Each one accepts an screen options props
<BottomTabs.Navigator screenOptions={{ headerShown: false }}>
or
<TrackStack.Navigator screenOptions={{ headerShown: false }}>
One of these needed to be false and the other true

react-navigation go Back not navigate to previous screen

I'm using new react-navigation 2.16.0 in my react-native app.
I have welcome (login and register) screen and then Main stack. main stack include all screens after success auth(login\register).
MainStack = createStackNavigator(
{
Welcome: {
screen: Welcome, navigationOptions: {
gesturesEnabled: false,
}
},
Main: {
screen: App, navigationOptions: {
gesturesEnabled: false,
}
}
}, {
headerMode: 'none',
lazy: true,
initialRouteName: UserStore.token ? 'Main' : 'Welcome',
gesturesEnabled: false,
cardStack: {
gesturesEnabled: false
},
cardStyle: {
elevation: 0,
shadowOpacity: 0,
borderBottomWidth: 0,
borderTopWidth: 0
},
transitionConfig: () => ({
containerStyle: {
elevation: 0,
shadowOpacity: 0,
borderBottomWidth: 0,
borderTopWidth: 0
}
}),
}
)`
Main stack render
render() {
// const splashDone = this.state.splashDone && this.state.backSplash
const ready = UserStore.storeHydrated
console.log('Current Routes', NavigationStore)
// console.log('AppStore.loading ', AppStore.loading)
return (
<View style={{ flex: 1,backgroundColor:'transparent'}}>
<StatusBar
barStyle="light-content"
/>
{!splashDone ? <SplashScreen /> : null}
{ready &&
<Provider {...stores}>
<MainStack
/>
</Provider>}
<InternetConnectionPopUp />
{AppStore.loading ?
<Spinner
color={colors.yellow}
style={{ position: 'absolute', right: 0, left: 0, top: 0, bottom: 0, zIndex: 99999 }} />
: null}
<View style={Platform.OS === 'ios' && this.state.flag ? { height: calcSize(25) } : {}} />
</View>
)
}
App.js
import React, { Component } from 'react'
import { BackHandler, Alert, AppState, View,Keyboard } from 'react-native'
import { inject, observer } from 'mobx-react/native'
import { AppStack } from '../../routes'
import { NavigationActions } from 'react-navigation'
import { Header } from '../../components';
let popupOpen = false
#inject('AppStore') #observer
class App extends Component {
constructor(props) {
super(props)
this.state = {
appState: AppState.currentState,
nowMounted: false
}
this.goBack = this.goBack.bind(this)
}
goBack() {
this.props.navigation.goBack(null)
}
componentWillMount() {
this.setState({ nowMounted: true })
}
render() {
return (
<View style={{ flex: 1 }}>
<Header onPressBack={this.goBack}/>
<AppStack/>
</View>
)
}
}
export default App
AppStack.js
import {
Dashboard,
Services,
Schedule,
ScheduleDays,
ScheduleTime,
CancelAppointment
} from '../screens'
import { createStackNavigator, NavigationActions } from 'react-navigation'
export const AppStack = createStackNavigator({
Dashboard: { screen: Dashboard, navigationOptions: {
gesturesEnabled: false,
} },
Services: { screen: Services, navigationOptions: {
gesturesEnabled: false,
} },
Schedule: { screen: Schedule, navigationOptions: {
gesturesEnabled: false,
} },
ScheduleDays: { screen: ScheduleDays, navigationOptions: {
gesturesEnabled: false,
} },
ScheduleTime: { screen: ScheduleTime, navigationOptions: {
gesturesEnabled: false,
} },
CancelAppointment: { screen: CancelAppointment, navigationOptions: {
gesturesEnabled: false,
} },
}, {
headerMode: 'none',
initialRouteName: 'Dashboard',
lazy: true,
gesturesEnabled: false,
cardStack: {
gesturesEnabled: false
},
})
goBack not works in createStackNavigator, it stay in same screen.
go Back not works at all.
when I navigate from dashboard to services screen and then press onBack in services it do nothing.
I also tried to change instead of createStackNavigator to createSwitchNavigator but still it not works.
Could you please put the code of the service screen where you call the goBack function, it could be helpful.
Generally you just call
this.props.navigation.goBack()
or
this.props.navigation.goBack(null)
you can also try
this.props.navigation.navigate('Dashboard')
if it's in the history of the stack it will go back to the previous screen from service screen instead of pushing it on top
This work for me.
<Button
title="go back"
onPress={(props) => { this.props.navigation.goBack(null) }}
/>
Dont forget to remove this for functional component.
Functional Component Approach
import {StyleSheet,Text,View,TouchableOpacity,} from 'react-native';
const ScreenName = ({ navigation }) => {
return (
<View style={styles.container}>
<TouchableOpacity onPress={() => navigation.goBack()}>
<Text>
GoBack
</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container:{
flex:1,
display: 'flex',
justifyContent:'center',
alignItems: 'center',
}
});
export default ScreenName;
Navigation prop has a goBack helper.
class HomeScreen extends React.Component {
render() {
const {goBack} = this.props.navigation;
return (
<View>
<Text>This is the home screen of the app</Text>
<Button
onPress={() => goBack()}
title="Go to Brent's profile"
/>
</View>
)
}
}

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

How can TabNavigator child screen refer to parent StackNavigator?

The structure of the application is this.
StackNavigator
StackA-Screen(TabNavigator)
TabChildA-Screen
TabChildB-Screen
...
StackB-Screen
code in App.js
const TabComponent = TabNavigator(
{
TabChildA-Screen: {
screen: TabChildA,
},
TabChildB-Screen: {
screen: TabChildB,
}
},
{
tabBarPosition: "bottom",
animationEnabled: false,
swipeEnabled: false
}
);
const StackComponent = StackNavigator(
{
StackA-Screen: {
screen: TabComponent,
navigationOptions: ({ navigation }) => ({
headerBackTitle: null,
headerRight: (
<TouchableWithoutFeedback
onPress={() =>
navigation.navigate("StackB-Screen", { space: "" }) // can't navigate to "StackB-Screen".
}
>
<MaterialIcon
name="playlist-add"
size={Sizes.NavigationBar.Icon.Size}
style={{ padding: 8, color: Colors.White }}
/>
</TouchableWithoutFeedback>
)
})
},
StackB-Screen: {
screen: StackB,
}
},
{
initialRouteName: "StackA-Screen",
mode: "modal"
}
);
export default StackComponent;
I want to navigate TabChildA-Screen to StackB-Screen.
But, TabChildA-Screen can refer to navigator is navigator of TabNavigator.
code in TabChildA-Screen
import React, { Component } from "react";
import { Button, Text, View } from "react-native";
class StackB extends Component {
constructor(props) {
super(props);
}
render() {
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center"
}}
>
<Button
onPress={ () =>
this.props.navigation.navigate("StackB-Screen") // can't navigate to "StackB-Screen".
}
title="move to StackB-Screen"
/>
</View>
);
}
}
export default StackB;
How to TabChildA-Screenrefer StackNavigator ?

react-navigation Cannot read property 'type' of null error in reducer

Project
I am developing draw navigation with reactive navigation. (using redux)
Stack and tap nested navigation work fine
Error
If I add nested drawer navigation, the reducer throws an error.
The error screen is shown below.
This is my full code
https://bitbucket.org/byunghyunpark/luxlab-user-2/commits/all
Error related code
src/navigation/index.js
import React, { Component } from "react";
import { BackHandler } from "react-native";
import { connect } from "react-redux";
import { StackNavigator, DrawerNavigator, addNavigationHelpers, NavigationActions } from "react-navigation";
import NavigationStack from "./navigationStack";
class AppNavigation extends Component {
componentDidMount() {
BackHandler.addEventListener("hardwareBackPress", this.onBackPress);
}
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", this.onBackPress);
}
onBackPress = () => {
const { dispatch, navigationState } = this.props;
if (navigationState.stateForLoggedIn.index <= 1) {
BackHandler.exitApp();
return;
}
dispatch(NavigationActions.back());
return true;
};
render() {
const { navigationState, dispatch, isLoggedIn } = this.props;
const state = isLoggedIn
? navigationState.stateForLoggedIn
: navigationState.stateForLoggedOut;
return (
<NavigationStack navigation={addNavigationHelpers({ dispatch, state })}/>
);
}
}
const mapStateToProps = state => {
return {
isLoggedIn: state.loginReducer.isLoggedIn,
navigationState: state.navigationReducer
};
};
export default connect(mapStateToProps)(AppNavigation);
src/navigation/navigationStack.js
import { Platform, StyleSheet, Text, View, AsyncStorage, ScrollView } from 'react-native';
import { StackNavigator, TabNavigator, DrawerNavigator, DrawerItems } from 'react-navigation';
import MyRepairWait from '../components/repair/myRepairWait';
import MyRepairProgress from '../components/repair/myRepairProgress';
import MyRepairComplete from '../components/repair/myRepairComplete';
import MySalesWait from '../components/sales/mySalesWait';
import MySalesComplete from '../components/sales/mySalesComplete';
import Home from '../components/home';
import ProductList from '../components/buy/productList';
import PartnerList from '../components/map/partnerList';
import Login from '../components/member/login';
const MyRepairListTab = TabNavigator({
wait: { screen: MyRepairWait, navigationOptions: { tabBarLabel: '문의중' } },
progress: { screen: MyRepairProgress, navigationOptions: { tabBarLabel: '진행중' } },
complete: { screen: MyRepairComplete, navigationOptions: { tabBarLabel: '완료' } }
},
{
tabBarPosition: 'top',
swipeEnabled: true,
animationEnabled: false,
tabBarOptions: {
activeTintColor: '#e91e63',
},
backBehavior: 'none',
}
)
const MySalesListTab = TabNavigator({
wait: { screen: MySalesWait, navigationOptions: { tabBarLabel: '문의중' } },
complete: { screen: MySalesComplete, navigationOptions: { tabBarLabel: '완료' } }
},
{
tabBarPosition: 'top',
swipeEnabled: true,
animationEnabled: false,
tabBarOptions: {
activeTintColor: '#e91e63',
},
backBehavior: 'none',
}
)
const baseRoutes = {
home: { screen: Home },
productList: { screen: ProductList },
myRepairList: { screen: MyRepairListTab },
mySalesList: { screen: MySalesListTab },
partnerList: { screen: PartnerList },
login: { screen: Login },
};
const DrawerRoutes = {
Home: {
name: 'Home',
screen: StackNavigator(baseRoutes, { initialRouteName: 'home' })
},
ProductList: {
name: 'ProductList',
screen: StackNavigator(baseRoutes, { initialRouteName: 'productList' })
},
MyRepairList: {
name: 'MyRepairList',
screen: StackNavigator(baseRoutes, { initialRouteName: 'myRepairList' })
},
MySalesList: {
name: 'MySalesList',
screen: StackNavigator(baseRoutes, { initialRouteName: 'mySalesList' })
},
};
const DrawerNavigatorConfig = {
drawerWidth: 300,
drawerPosition: 'right',
contentComponent: props => <ScrollView><DrawerItems {...props} /></ScrollView>,
contentOptions: {
activeTintColor: '#e91e63',
itemsContainerStyle: {
marginVertical: 0,
},
iconContainerStyle: {
opacity: 1
}
}
}
const navigator =
StackNavigator(
{
Drawer: {
name: 'Drawer',
screen: DrawerNavigator(
DrawerRoutes,
DrawerNavigatorConfig
),
},
...navigator
},
{
headerMode: 'none'
}
);
export default navigator;
src/reducers/index.js
import { combineReducers } from 'redux';
import navigationReducer from './navigationReducer';
import loginReducer from './loginReducer';
const AppReducer = combineReducers({
navigationReducer,
loginReducer
});
export default AppReducer;
src/reducers/navigationReducer.js
import { NavigationActions } from "react-navigation";
import AppNavigator from "../navigation/navigationStack";
import { Login, Logout } from "../actions/actionTypes";
const ActionForLoggedOut = AppNavigator.router.getActionForPathAndParams(
"login"
);
const ActionForLoggedIn = AppNavigator.router.getActionForPathAndParams(
"home"
);
const stateForLoggedOut = AppNavigator.router.getStateForAction(
ActionForLoggedOut
);
const stateForLoggedIn = AppNavigator.router.getStateForAction(
ActionForLoggedIn
);
const initialState = { stateForLoggedOut, stateForLoggedIn };
const navigationReducer = (state = initialState, action) => {
switch (action.type) {
case "##redux/INIT":
return {
...state,
stateForLoggedIn: AppNavigator.router.getStateForAction(
ActionForLoggedIn,
stateForLoggedOut
)
};
case Login:
return {
...state,
stateForLoggedIn: AppNavigator.router.getStateForAction(
ActionForLoggedIn,
stateForLoggedOut
)
};
case Logout:
return {
...state,
stateForLoggedOut: AppNavigator.router.getStateForAction(
NavigationActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: "login" })]
})
)
};
default:
return {
...state,
stateForLoggedIn: AppNavigator.router.getStateForAction(
action,
state.stateForLoggedIn
)
};
}
};
export default navigationReducer;
src/components/home.js
import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View, Button, ImageBackground, TouchableHighlight, Image, ScrollView, Alert, CameraRoll, AsyncStorage } from 'react-native';
import { NavigationActions } from "react-navigation";
import Icon from 'react-native-vector-icons/FontAwesome';
import { connect } from 'react-redux';
const styles = StyleSheet.create({
container: {
flex: 1,
},
mainPhoto: {
flex: 1,
margin: 10,
marginBottom: 0,
justifyContent: 'center',
},
mainPhotoEnd: {
marginBottom: 10
},
mainOpacity: {
flex: 1,
backgroundColor: 'rgba(0,0,0,0.5)',
},
mainTitle: {
color: 'white',
fontSize: 30,
marginTop: 20,
marginLeft: 20,
marginRight: 20,
fontWeight: '700',
},
mainDescription: {
flex: 2.3,
marginTop: 5,
marginLeft: 20,
marginRight: 20,
color: 'white',
fontSize: 15,
fontWeight: '400',
},
alignRight: {
textAlign: 'right'
},
backgroundWhite: {
flex: 1,
backgroundColor: 'white'
},
headerRight: {
padding: 10
},
headerLeft: {
padding: 20
}
});
class HomeScreen extends React.Component {
navigate1 = () => {
console.log('click navigate1');
const navigate1 = NavigationActions.navigate({
routeName: "partnerList",
params: { name: "Shubhnik" }
});
this.props.navigation.dispatch(navigate1);
};
navigate2 = () => {
console.log('click navigate2');
const navigate2 = NavigationActions.navigate({
routeName: "myRepairList",
params: { name: "Shubhnik" }
});
this.props.navigation.dispatch(navigate2);
};
static navigationOptions = ({navigation}) => ({
drawerLabel: () => null,
title: 'LUXLAB',
headerStyle: {
backgroundColor: '#fff',
borderBottomWidth: 0,
elevation: 0,
},
headerTitleStyle: {
color: '#000',
fontSize: 20,
textAlign: 'center',
alignSelf: 'center',
},
headerRight: <Icon name="bars" size={30} color="#333" onPress={() => navigation.navigate('DrawerOpen')} style={styles.headerRight}/>,
headerLeft: <Icon name="map-marker" size={30} color="#333" onPress={() => navigation.navigate('partnerList')} style={styles.headerLeft} />
})
async componentDidMount() {
let user_info = await AsyncStorage.getItem('user_info');
user_info = JSON.parse(user_info).key;
console.log('storage1', user_info.key);
console.log('isloggedIn', this.props.isLoggedIn);
}
render() {
return (
<View style={styles.backgroundWhite}>
<TouchableHighlight
style={styles.container}
underlayColor="#fff"
onPress={this.navigate1}>
<ImageBackground
source={require('../assets/imgs/main1.jpg')}
style={[styles.mainPhoto, styles.mainOpacity]}>
<View style={styles.mainOpacity}>
<Text style={styles.mainTitle}>중고 명품 구매</Text>
<Text style={styles.mainDescription}>검증받은 다양한 명품들을{"\n"}간편하게 볼 수 있습니다</Text>
</View>
</ImageBackground>
</TouchableHighlight>
<TouchableHighlight
style={styles.container}
underlayColor="#fff"
onPress={this.navigate2}>
<ImageBackground
source={require('../assets/imgs/main2.jpg')}
style={styles.mainPhoto}>
<View style={styles.mainOpacity}>
<Text style={[styles.mainTitle, styles.alignRight]}>수선 견적 문의</Text>
<Text style={[styles.mainDescription, styles.alignRight]}>몇 가지 정보 입력으로{"\n"}수선 견적을 받아보세요</Text>
</View>
</ImageBackground>
</TouchableHighlight>
<TouchableHighlight
style={styles.container}
underlayColor="#fff"
onPress={this.navigate1}>
<ImageBackground
source={require('../assets/imgs/main3.jpg')}
style={[styles.mainPhoto, styles.mainPhotoEnd]}>
<View style={styles.mainOpacity}>
<Text style={styles.mainTitle}>중고 명품 판매</Text>
<Text style={styles.mainDescription}>몇 가지 정보 입력으로{"\n"}매매 견적을 받아보세요</Text>
</View>
</ImageBackground>
</TouchableHighlight>
</View>
)
}
}
const mapStateToProps = state => ({
isLoggedIn: state.loginReducer.isLoggedIn
});
const Home = connect(mapStateToProps, null)(HomeScreen);
export default Home;
Thanks!