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
Related
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>
);
}
}
I have setup my StackNavigator like so:
const AppNavigator = StackNavigator(
{
Home: {
screen: HomeScreen
},
Month: {
screen: Month
},
Day: {
screen: Day
}
},
{
headerMode: "screen",
navigationOptions: {
header: props => <CustomHeader {...props} />
}
}
);
I can navigate from each screen using this.props.navigation.navigate("Month");
However, in my CustomHeader, I cannot see this prop navigate to invoke. I need to navigate back to the home screen using a button in my header.
resetForm() {
const {
resetForm,
clearCredentials,
navigation
} = this.props;
this.props.navigation.navigate("Home");
}
How can I access the navigate prop to move to another screen?
CustomHeader in full:
import React, { Component } from "react";
import { connect } from "react-redux";
import {
Image,
View,
Text,
Modal,
Button,
TouchableOpacity,
AsyncStorage,
StyleSheet,
Platform,
Alert,
TouchableHighlight
} from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { NavigationActions } from "react-navigation";
import {
setYear,
setStudent,
setGroup,
fetchCategories,
resetForm,
resetData,
fetchEvents
} from "../actions/events";
class CustomHeader extends Component {
constructor() {
super();
this.resetForm = this.resetForm.bind(this);
this.fetchEvents = this.fetchEvents.bind(this);
this.showAlert = this.showAlert.bind(this);
}
resetForm() {
const navigateAction = NavigationActions.navigate({
routeName: "Home",
params: {},
action: NavigationActions.navigate({ routeName: "Home" })
});
this.props.dispatch(navigateAction);
}
showAlert() {
Alert.alert("Events refreshed");
}
fetchEvents() {
const {
fetchEvents,
navigate,
credentials: { group }
} = this.props;
resetData();
fetchEvents(group);
navigate("Month");
this.showAlert();
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={this.resetForm}>
<Image
source={require("../img/logout.png")}
style={{ width: 25, height: 30 }}
/>
</TouchableOpacity>
<TouchableOpacity onPress={this.fetchEvents}>
<Image
source={require("../img/refresh.png")}
style={{ width: 20, height: 30 }}
/>
</TouchableOpacity>
</View>
);
}
}
const mapDispatchToProps = dispatch => {
return {
resetForm: () => dispatch(resetForm()),
fetchEvents: id => dispatch(fetchEvents(id)),
resetData: () => dispatch(resetData())
};
};
const mapStateToProps = state => {
return {
categories: state.fetchCategories,
isLoading: state.isLoading,
credentials: state.setCredentials
};
};
export default connect()(CustomHeader);
You must pass navigation to navigationOptions to use in header component. Your AppNavigator should be like this
const AppNavigator = StackNavigator(
{
Home: {
screen: HomeScreen
},
Month: {
screen: Month
},
Day: {
screen: Day
}
},
{
headerMode: "screen",
navigationOptions: ({ navigation }) => ({
header: props => <CustomHeader {...props} navigation={navigation}/>
})
}
);
CustomHeader
...
resetForm() {
const {navigation} = this.props;
navigation.navigate("Home");
}
...
Why is this.props.navigation.navigate() not available in my component? In fact, this.props is completely empty? My setup is that App.js adds StartScreen.js and ListScreen.js to a stackNavigator. ListScreen.js is then used as a component in Startscreen.js and will serve as a stacknavigation...
ListScreen.js
import React, { Component } from "react";
import { ScrollView, View, Text, FlatList, ActivityIndicator } from "react-native";
import { List, ListItem } from 'react-native-elements';
import Styles from 'app/styles/Styles';
import Vars from 'app/vars/Vars';
class ListScreen extends Component {
/*
static navigationOptions = {
title: 'Välkommen',
headerStyle: Styles.header,
headerTintColor: Vars.colors.primary,
headerTitleStyle: Styles.headerTitle,
};
*/
constructor(props) {
super(props);
console.log(props);
this.state = {
loading: true,
data: [],
page: 1,
seed: 1,
error: null,
refreshing: false
};
}
componentDidMount() {
this.fetchItems();
}
fetchItems = () => {
const { page, seed } = this.state;
const url = 'http://appadmin.test/api/menu/'+this.props.id;
this.setState({ loading: true });
fetch(url)
.then(res => res.json())
.then(res => {
this.setState({
data: page === 1 ? res : [...this.state.data, ...res],
error: res.error || null,
loading: false,
refreshing: false
});
})
.catch(error => {
this.setState({ error, loading: false });
});
}
handleRefresh = () => {
console.log('several handleRefresh?');
this.setState(
{
page: 1,
seed: this.state.seed + 1,
refreshing: true
},
() => {
this.fetchItems();
}
);
};
handleLoadMore = () => {
console.log('several handleLoadMore?');
this.setState(
{
page: this.state.page + 1
},
() => {
this.fetchItems();
}
);
};
renderFooter = () => {
if (!this.state.loading) return null;
return (
<View
style={{
paddingVertical: 20,
}}
>
<ActivityIndicator animating size="large" />
<Text style={Styles.textCenter}>
Laddar innehåll...
</Text>
</View>
);
};
renderListItem = ({ item }) => (
<ListItem
title = {item.title}
id = {item.id}
automaticallyAdjustContentInsets={false}
item = {item}
leftIcon={{
name: item.icon,
style: Styles.listitemIcon,
size: 36,
}}
onPress = {this.onItemPress}
style = { Styles.listItem }
titleStyle = { Styles.listitemTitle }
/>
)
onItemPress = (item) => {
this.props.navigation.navigate('List', {
id: item.id
});
}
render() {
return (
<ScrollView contentContainerStyle={Styles.listContainer}>
<FlatList
automaticallyAdjustContentInsets={false}
data = { this.state.data }
style={Styles.list}
keyExtractor={item => "key_"+item.id}
renderItem = { this.renderListItem }
ListFooterComponent={this.renderFooter}
onRefresh={this.handleRefresh}
refreshing={this.state.refreshing}
onEndReachedThreshold={50}
/>
</ScrollView>
);
}
}
export default ListScreen;
StartScreen.js
import React, { Component } from "react";
import {
View,
ScrollView,
Text,
StyleSheet,
Linking,
FlatList
} from "react-native";
import Styles from 'app/styles/Styles';
import Vars from 'app/vars/Vars';
import ListScreen from 'app/screens/ListScreen';
import { List, ListItem } from 'react-native-elements';
import Menu from './../../assets/data/navigation.json';
class StartScreen extends Component {
static navigationOptions = {
title: 'Välkommen',
headerStyle: Styles.header,
headerTintColor: Vars.colors.primary,
headerTitleStyle: Styles.headerTitle,
};
constructor(props) {
super(props);
this.state = {
loading: false,
data: [],
page: 1,
seed: 1,
error: null,
refreshing: false,
};
}
componentDidMount() {
this.fetchList();
}
fetchList = () => {
const { page, seed } = this.state;
const url = 'http://appadmin.test/api/menu/root';
this.setState({ loading: true });
fetch(url)
.then(response => {
return response.json();
})
.then(json => {
this.setState({
data: json,
error: null,
loading: false,
refreshing: false
});
})
.catch(error => {
this.setState({ error, loading: false });
});
}
render() {
return (
<ScrollView style={Styles.scrollContainer}>
<View style={Styles.hero}>
<Text style={[Styles.h1, Styles.whiteText]}>
Region Halland
</Text>
<Text style={[Styles.lead, Styles.whiteText]}>
Välkommen
</Text>
</View>
<ListScreen id=""/>
</ScrollView>
);
}
}
export default StartScreen;
App.js
import React from 'react';
import {
StyleSheet,
Text,
View,
Image,
} from 'react-native';
import initCache from "app/utilities/initCache";
import { AppLoading } from 'expo';
import {
createBottomTabNavigator,
createStackNavigator
} from 'react-navigation'
import StartScreen from 'app/screens/StartScreen';
import ListScreen from 'app/screens/ListScreen';
import AboutScreen from 'app/screens/AboutScreen';
import { icon } from 'app/components/Image.js';
import Ionicons from 'react-native-vector-icons/Ionicons'
const StartStack = createStackNavigator({
Start: {screen: StartScreen, tabBarLabel: 'Hem'},
List: {screen: ListScreen},
}, {
navigationOptions : {
headerTitle: <Image
source={ icon }
style={{ width: 30, height: 30 }} />,
tabBarLabel: 'hem'
}
});
const AboutStack = createStackNavigator({
About: AboutScreen,
});
const Tabs = createBottomTabNavigator({
StartStack: {screen: StartStack, navigationOptions: { title: 'Hem'}},
AboutStack: {screen: AboutStack, navigationOptions: { title: 'Om Region Halland'}}
}, {
navigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, tintColor }) => {
const { routeName } = navigation.state;
let iconName;
if (routeName === 'AboutStack') {
iconName = `ios-information-circle${focused ? '' : '-outline'}`;
} else if (routeName === 'StartStack') {
iconName = `ios-home${focused ? '' : '-outline'}`;
}
// You can return any component that you like here! We usually use an
// icon component from react-native-vector-icons
return <Ionicons name={iconName} size={24} color={tintColor} />;
},
}),
tabBarOptions: {
activeTintColor: '#0b457e',
inactiveTintColor: 'gray',
},
})
export default class App extends React.Component {
state = {
appIsReady: false,
};
componentWillMount() {
this._loadAssetsAsync();
}
async _loadAssetsAsync() {
try {
await initCache({
fonts: [
{'scala-sans-regular': require('./assets/fonts/ScalaSans-Regular.ttf')},
{'scala-sans-bold': require('./assets/fonts/ScalaSans-Bold.ttf')},
]
});
} catch (e) {
console.warn(
'There was an error caching assets (see: main.js), perhaps due to a ' +
'network timeout, so we skipped caching. Reload the app to try again.'
);
console.log(e.message);
} finally {
this.setState({ appIsReady: true });
}
}
render() {
if (this.state.appIsReady) {
return (
<Tabs />
);
} else {
return <AppLoading />;
}
}
}
const { navigate } = this.props.navigation;
then use it as : navigate(‘Signup’)}
I'm having some issue with react-navigation.
My navigation routes :
StackNavigator: main app navigation
-- WelcomeScreen
-- GuideScreen
-- TabNavigator: this is CustomTabs
+ MyHomeScreen
+ MyNotificationsScreen
+ MySettingsScreen
-- OtherScreen.
I use createNavigator, createNavigationContainer to build my own Navigation. You can view live for custom tab here: https://snack.expo.io/rJnUK4nrZ
import React from 'react';
import {
Button,
Platform,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
import {
createNavigator,
createNavigationContainer,
TabRouter,
addNavigationHelpers,
} from 'react-navigation'; // 1.0.0-beta.11
const SampleText = ({ children }) => (
<Text style={styles.sampleText}>{children}</Text>
);
const MyNavScreen = ({ navigation, banner }) => (
<ScrollView>
<SampleText>{banner}</SampleText>
<Button
onPress={() => {
navigation.goBack(null);
}}
title="Go back"
/>
</ScrollView>
);
const MyHomeScreen = ({ navigation }) => (
<MyNavScreen banner="Home Screen" navigation={navigation} />
);
const MyNotificationsScreen = ({ navigation }) => (
<MyNavScreen banner="Notifications Screen" navigation={navigation} />
);
const MySettingsScreen = ({ navigation }) => (
<MyNavScreen banner="Settings Screen" navigation={navigation} />
);
const CustomTabBar = ({ navigation }) => {
const { routes } = navigation.state;
return (
<View style={styles.tabContainer}>
{routes.map(route => (
<TouchableOpacity
onPress={() => navigation.navigate(route.routeName)}
style={styles.tab}
key={route.routeName}
>
<Text>{route.routeName}</Text>
</TouchableOpacity>
))}
</View>
);
};
const CustomTabView = ({ router, navigation }) => {
const { routes, index } = navigation.state;
const ActiveScreen = router.getComponentForState(navigation.state);
return (
<View style={styles.container}>
<CustomTabBar navigation={navigation} />
<ActiveScreen
navigation={addNavigationHelpers({
...navigation,
state: routes[index],
})}
/>
</View>
);
};
const CustomTabRouter = TabRouter(
{
Home: {
screen: MyHomeScreen,
path: '',
},
Notifications: {
screen: MyNotificationsScreen,
path: 'notifications',
},
Settings: {
screen: MySettingsScreen,
path: 'settings',
},
},
{
// Change this to start on a different tab
initialRouteName: 'Home',
}
);
const CustomTabs = createNavigationContainer(
createNavigator(CustomTabRouter)(CustomTabView)
);
const styles = StyleSheet.create({
container: {
marginTop: Platform.OS === 'ios' ? 20 : 0,
},
tabContainer: {
flexDirection: 'row',
height: 48,
},
tab: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
margin: 4,
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 4,
},
sampleText: {
margin: 14,
},
});
export default CustomTabs;
In the App.js
import { connect } from "react-redux";
import { addNavigationHelpers, StackNavigator } from "react-navigation";
import Welcome from "#components/WelcomeScreen";
import Welcome from "#components/GuideScreen";
import Welcome from "#components/OtherScreen";
// import CustomTabs
export const AppNavigator = StackNavigator(
{
Welcome: { screen: WelcomeScreen },
Guide: { screen: GuideScreen },
Home: { screen: CustomTabs }, // I want to use CustomTabs TabNavigation here?
Other: { screen: OtherScreen },
},
{
initialRouteName: "Welcome",
headerMode: "none"
}
);
const Routes= ({ dispatch, nav }) => (
<AppNavigator navigation={addNavigationHelpers({ dispatch, state: nav })} />
);
const mapStateToProps = state => ({
nav: state.nav
});
const mapDispatchToProps = dispatch => ({
dispatch
});
export default connect(mapStateToProps, mapDispatchToProps)(AppWithNavigationState);
How to add my custom TabNavigator to main StackNavigator?
What I'm doing wrong? The app integrated with redux, saga. If you have other example about custom stack and tab using react-navigation, please give me to reference.
Update Your Code:
import Tab1Screen from "#components/Tab1Screen"
import Tab2Screen from "#components/Tab2Screen"
export const AppNavigator = StackNavigator(
{
Welcome: { screen: WelcomeScreen },
Guide: { screen: GuideScreen },
Home: {
screen: TabNavigator(
{
Tab1Screen: {screen: Tab1Screen},
Tab2Screen: {screen: Tab2Screen}
},{
tabBarPosition: "bottom"
})
},
Other: { screen: OtherScreen },
},
{
initialRouteName: "Welcome",
headerMode: "none"
}
);
We can access TabNavigation inside of StackNavigtion
import files
import SampleHeadersScreen from "../Containers/SampleHeadersScreen";
import SampleHeaders1Screen from "../Containers/SampleHeaders1Screen";
import SampleHeaders3Screen from "../Containers/SampleHeaders3Screen";
import SampleHeaders8Screen from "../Containers/SampleHeaders8Screen";
import SampleHeaders9Screen from "../Containers/SampleHeaders9Screen";
const TabSegment = TabNavigator(
{
SegmentBarScreen: {
screen: SampleHeaders8Screen,
navigationOptions: {
title: "Album"
}
},
SegmentBarScreen1: {
screen: SampleHeaders9Screen,
navigationOptions: {
title: "Other"
}
}
})
const PrimaryNav = StackNavigator(
{
LaunchScreen: { screen: LaunchScreen },
SampleHeadersScreen: { screen: SampleHeadersScreen },
SampleHeaders1Screen: { screen: SampleHeaders1Screen },
SampleHeaders3Screen: { screen: SampleHeaders3Screen },
//TabNavigaion
SampleSegmentTab: { screen: TabSegment },
})
Give TabSegment in side the stack nativion.
It work well. I hope it will help you.
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!