React Navigation - Cannot read property 'navigation' of undefined - javascript

I am trying to get my button in the header to navigate to a gallery of images. When I press the button, I get "Cannot read property 'navigation' of undefined. Both of these files are in the same folder, which is "Profiles". Anybody know what this errors means and how to possibly fix it?
This is how I have the button set up in my headerRight.
//HomerSimpson.js
import React from "react";
import {
Button,
View,
Text,
StyleSheet,
Image,
List,
ListItem,
ImageBackground
} from "react-native";
import { withNavigation } from 'react-navigation';
import HomerGallery from "./Profiles/HomerGallery";
class HomerSimpson extends React.Component {
static navigationOptions = {
title: "Homer Simpson Profile",
headerStyle: {
backgroundColor: "#53b4e6"
},
headerTintColor: "#f6c945",
headerTitleStyle: {
fontWeight: "bold"
},
headerRight: (
<Button
onPress={() => this.props.navigation.navigate("HomerGallery")}
title="Gallery"
color="#f6c945"
/>
)
};
I made a separate component for the gallery itself and it's in the same folder as HomerSimpson.js.
//HomerGallery.js
import React from "react";
import {
Button,
View,
Text,
StyleSheet,
Image,
List,
ListItem,
ImageBackground
} from "react-native";
import ImageSlider from 'react-native-image-slider';
class HomerGallery extends React.Component {
static navigationOptions = {
title: "Homer's Gallery",
headerStyle: {
backgroundColor: "#53b4e6"
},
headerTintColor: "#f6c945",
headerTitleStyle: {
fontWeight: "bold"
},
headerRight: <Button onPress={() => alert("Bart loves to skateboard")} title="Facts" color="#f6c945" />
};
render() {
return (<ImageSlider images={[
'https://i.pinimg.com/474x/f1/36/ca/f136ca04817e60fa12f4a5680101ff8b.jpg',
'https://i.pinimg.com/474x/b1/da/e2/b1dae2fe6ca1620e5d1949a2dcd33a0c.jpg',
'https://i.pinimg.com/564x/7b/53/32/7b5332ef6a981b3c54e855495ea1c828.jpg',
'https://i.pinimg.com/564x/f4/71/79/f471798aeeae427474f544691d572970.jpg',
'https://i.pinimg.com/564x/32/3d/53/323d534f07de7d9ebeb58ede1f87d63e.jpg'
]}/>)
};
}
export default HomerGallery;
The route for the gallery is "HomerGallery". Here is how it's set up in my navigation file. It's imported, but I'll leave those il
import HomerGallery from "../../Profiles/HomerGallery";
import { createStackNavigator, createAppContainer } from "react-navigation";
const AppNavigator = createStackNavigator(
{
Login: Login,
Home: HomeScreen,
Details: DetailsScreen,
Bio: BioScreen,
EmployeeDirectory: EmployeeDirectory,
HomerSimpson: HomerSimpson,
BartSimpson: BartSimpson,
MargeSimpson: MargeSimpson,
LisaSimpson: LisaSimpson,
MaggieSimpson: MaggieSimpson,
SantasHelper: SantasHelper,
BarneyGumble: BarneyGumble,
MrBurns: MrBurns,
KentBrockman: KentBrockman,
RalphWiggum: RalphWiggum,
OttoMan: OttoMan,
Scratchy: Scratchy,
HomerGallery: HomerGallery,
BallBounce: BallBounce,
OverlayPage: OverlayPage,
Rankings: Rankings
},
{
initialRouteName: "HomerSimpson",
defaultNavigationOptions: {
headerStyle: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
},
);
export default createAppContainer(AppNavigator);

HomerSimpson.js
export default withNavigation(HomerSimpson)
This should pass all the necessary navigation props.

I think this is the offending line onPress={() => this.props.navigation.navigate("HomerGallery")}. The static object navigationOptions won't have access to this.props of the component.
You don't mention React Navigation, but I'm guessing that's what you're using. Here's an example from their docs that shows how you can access props by using a function instead of an object. Good luck!
static navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('otherParam', 'A Nested Details Screen'),
};
}
Update
Example applied to your code:
navigationOptions = ({ navigation }) => ({
title: "Homer Simpson Profile",
headerStyle: {
backgroundColor: "#53b4e6"
},
headerTintColor: "#f6c945",
headerTitleStyle: {
fontWeight: "bold"
},
headerRight: (
<Button
onPress={() => navigation.navigate("HomerGallery")}
title="Gallery"
color="#f6c945"
/>
)
});

Related

Is there a way to navigate to a different screen from the menu built in my Parent Component?

I am trying to add a simple customized navigation menu to my react-native app, but the issue that I am coming across right now is that I can't seem to find a way to navigate to the selected menu items corresponding screen. I tried the normal this.props.navigation.navigate('Home'), but it seems that there is no navigation prop, which makes sense because in my app I am assuming that the prop for navigation is passed down to the screens from my app.js through the use of <AppContainer />.
I have tried using the MainNavigator object in my App.js but it doesn't seem to be working and doesn't have a navigate function or anything like that.
I have also tried changing the structure of my render function in App.js a little bit but it still does not seem to be having much of an effect.
This is my App.js
import React, { Component } from 'react';
import {
View,
Text,
TouchableOpacity
} from 'react-native';
import {
createStackNavigator,
createAppContainer } from 'react-navigation';
// SCREEN
import MainScreen from './screens/MainScreen';
import CostAnalysis from './screens/CostAnalysis';
import DriverLog from './screens/DriverLog';
// SIDE MENU
import SideMenu from 'react-native-side-menu';
// REDUX IMPORTS
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { recordReducer } from './reducers/recordReducer';
import { databaseReducer } from './reducers/databaseReducer';
const MainNavigator = createStackNavigator({
Home: {screen: MainScreen},
DriverLog: {screen: DriverLog},
CostAnalysis: {screen: CostAnalysis},
}, {
defaultNavigationOptions: {
header: null
}
});
const AppContainer = createAppContainer(MainNavigator);
const rootReducer = combineReducers(
{records: recordReducer,
database: databaseReducer});
const store = createStore(rootReducer);
class App extends Component {
render() {
const menu = (<View style={{
backgroundColor: '#f0f0f0',
alignContent: 'center',
textAlign: 'center', height: '100%', width: '100%', paddingTop: '40%'}}>
<Text style={styles.menuTitle}>{'S K I P\nD R I V E R\nL O G'}</Text>
<TouchableOpacity onPress={() => {this.props.navigation.navigate('Home')}}>
<Text style={styles.menuItem}>HOME</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => {MainNavigator.navigate('DriverLog')}}>
<Text style={styles.menuItem}>DRIVING LOG</Text>
</TouchableOpacity>
</View>);
return (
<SideMenu menu={menu} >
<Provider store={store}>
<AppContainer />
</Provider>
</SideMenu>
);
}
}
const styles = {
menuTitle: {
marginBottom: 60,
fontSize: 40,
textAlign: 'center',
color: '#e74c3c'
},
menuItem: {
marginBottom: 10,
fontSize: 26,
textAlign: 'center'
}
}
export default (App);
Ideally I don't have to re-structure my entire app as I have made a lot of progress in other areas, but I would really like the menu to simply link to the correct places.
I'm still very new to react-native so I really don't know what else to try. If anyone can give me a hand it would be greatly appreciated!
Thanks :)
PS: See a picture of the menu to illustrate what I mean
Menu Screenshot
you have to implement the constructor
class App extends Component {
constructor(props) {
super(props);
}
}
or
if you are using a drawer use it as a separate component
import React, { Component } from 'react';
import {
View,
Text,
TouchableOpacity
} from 'react-native';
class SideDrawer extends Component{
constructor(props) {
super(props);
}
render(){
return(
<View style={{
backgroundColor: '#f0f0f0',
alignContent: 'center',
textAlign: 'center', height: '100%', width: '100%', paddingTop: '40%'}}>
<Text style={styles.menuTitle}>{'S K I P\nD R I V E R\nL O G'}</Text>
<TouchableOpacity onPress={() => {this.props.navigation.navigate('Home')}}>
<Text style={styles.menuItem}>HOME</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => {MainNavigator.navigate('DriverLog')}}>
<Text style={styles.menuItem}>DRIVING LOG</Text>
</TouchableOpacity>
</View>
)
}
}
export default sideDrawer
then in your navigator
const HomeNavigator = StackNavigator(
Home: {screen: MainScreen},
DriverLog: {screen: DriverLog},
CostAnalysis: {screen: CostAnalysis},
}
const MainNavigator = DrawerNavigator({
Home: {
screen: HomeNavigator,
},
}, {
contentComponent: sideDrawer,
drawerWidth: width * .7,
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
});

How To navigate from createMaterialTopTabNavigatorto other screen - React Navigation?

I have some issue when navigating from top Tabnavigator to other screens
so my app navigation is
My Orders Screen from Drawer => Top TabNavigatore (Accepted/Completed) => Order Details
In Route.js
I put every single navigation I want like Drawer - Auth navigation and so on, and I put a StackNavigator contain the Orders Screen like this:
const OrdersStack = createStackNavigator({
Orders: {
screen: Orders,
navigationOptions: ({ navigation }) => ({
headerLeft: (
// <TouchableOpacity onPress={() => navigation.dispatch(DrawerActions.toggleDrawer())}>
<TouchableOpacity
onPress={() => navigation.dispatch(DrawerActions.toggleDrawer())}
>
<Icon
name="ios-menu"
size={40}
style={{ margin: 10 }}
color="#2F98AE"
/>
</TouchableOpacity>
),
headerRight: <View />,
title: "My Orders",
headerTintColor: "#2F98AE",
headerStyle: {
borderBottomColor: "white"
},
headerTitleStyle: {
color: "#2F98AE",
// textAlign: "center",
flex: 1,
elevation: 0,
fontSize: 25
// justifyContent: "center"
}
})
}
});
In the Orders.js I put these:
import React, { Component } from "react";
import { createAppContainer, createStackNavigator } from "react-navigation";
import NavTabs from "../screens/NavTabs";
import NavOrderDetails from "../screens/NavOrderDetails";
// create a component
export default class Orders extends Component {
render() {
return <MyOrdersScreen />;
}
}
export const root = createStackNavigator({
NavTabs: NavTabs,
NavOrderDetails: NavOrderDetails
});
const MyOrdersScreen = createAppContainer(root);
As I mentioned in Orders.js it Contains Tabs and Order Details
In Tabs, I'm creating a createMaterialTopTabNavigator
import { createMaterialTopTabNavigator } from "react-navigation";
import AcceptedOrders from "../screens/AcceptedOrders";
import CompletedOrders from "../screens/CompletedOrders";
const MainTabs = createMaterialTopTabNavigator(
{
Accepted: { screen: AcceptedOrders },
Completed: { screen: CompletedOrders }
},
{
tabBarOptions: {
activeTintColor: "#fff",
inactiveTintColor: "#ddd",
tabStyle: {
justifyContent: "center"
},
indicatorStyle: {
backgroundColor: "#fcc11e"
},
style: {
backgroundColor: "#2F98AE"
}
}
}
);
export default MainTabs;
and another screen is OrderDeatils.js
import { createStackNavigator } from "react-navigation";
import OrderDetails from "../screens/OrderDetails";
import React, { Component } from "react";
import { View } from "react-native";
const OrderDetailsStack = createStackNavigator({
OrderDetails: {
screen: OrderDetails,
navigationOptions: () => ({
title: "Order Details",
headerRight: <View />,
headerTintColor: "#2F98AE",
headerStyle: {
borderBottomColor: "white"
},
headerTitleStyle: {
color: "#2F98AE",
flex: 1,
elevation: 0,
fontSize: 25
}
})
}
});
export default OrderDetailsStack;
Here are a screenShots it should explain what I mean
1- My Orders
2- Order Details
If i understand, you are concerned about the blank header that appears on top of the screen under your first header.
That one is created by createStackNavigator.
A the first Stack that creates the first Header named OrdersStack.
Inside that you have the root constant (probably, as there isn't the full code) that is creating the second header.
Inside root you are then defining your createMaterialTopTabNavigator with your two screens, that's showing the topBar with the label "accepted" and "completed".
To hide that white space you have to disable your root header doing:
export const root = createStackNavigator({
NavTabs: NavTabs,
NavOrderDetails: NavOrderDetails
},
{
defaultNavigationOptions:{
header:null
}
});
UPDATE.
You have two ways to fix this and still have a backButton:
1) You can either create a parent CustomHeader that, using react-navigation's withNavigation HOC, is aware about his childrens navigation state.
2) Dinamically hide the parent header when the second one is showing. You can accomplish this using this.props.navigation.dangerouslyGetParent().dangerouslyGetParent().setParams({showHeader:false})
then your OrdersStack would be:
const OrdersStack = createStackNavigator({
Orders: {
screen: Orders,
navigationOptions: ({ navigation }) => {
var defaultHeader={
headerLeft: (
<TouchableOpacity
onPress={() => navigation.dispatch(DrawerActions.toggleDrawer())}
>
<Icon
name="ios-menu"
size={40}
style={{ margin: 10 }}
color="#2F98AE"
/>
</TouchableOpacity>
),
headerRight: <View />,
title: "My Orders",
headerTintColor: "#2F98AE",
headerStyle: {
borderBottomColor: "white"
},
headerTitleStyle: {
color: "#2F98AE",
// textAlign: "center",
flex: 1,
elevation: 0,
fontSize: 25
// justifyContent: "center"
}
}
if (navigation.state.params)
return(navigation.state.params.showHeader?{defaultHeader}:null)
else return defaultHeader
}
}
});

How to export a class using DrawerNavigation and import it in another class in React-native?

In my React- Native project , I have App.js file as my default class. In this is class I have used DrawerNavigation. Here I have provided the code for my App.js class-
App.js
import React, { Component } from 'react';
import { View, Image, TouchableOpacity } from 'react-native';
import {
createDrawerNavigator,
createStackNavigator,
createAppContainer,
} from 'react-navigation';
import Screen1 from './pages/Screen1';
import Screen2 from './pages/Screen2';
import Screen3 from './pages/Screen3';
class NavigationDrawerStructure extends Component {
toggleDrawer = () => {
this.props.navigationProps.toggleDrawer();
};
render() {
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity onPress={this.toggleDrawer.bind(this)}>
{/*Donute Button Image */}
<Image
source={require('./image/drawer.png')}
style={{ width: 25, height: 25, marginLeft: 5 }}
/>
</TouchableOpacity>
</View>
);
}
}
const FirstActivity_StackNavigator = createStackNavigator({
First: {
screen: Screen1,
navigationOptions: ({ navigation }) => ({
title: 'Demo Screen 1',
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
});
const Screen2_StackNavigator = createStackNavigator({
Second: {
screen: Screen2,
navigationOptions: ({ navigation }) => ({
title: 'Demo Screen 2',
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
});
const Screen3_StackNavigator = createStackNavigator({
Third: {
screen: Screen3,
navigationOptions: ({ navigation }) => ({
title: 'Demo Screen 3',
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
});
const DrawerNavigatorExample = createDrawerNavigator({
Screen1: {
//Title
screen: FirstActivity_StackNavigator,
navigationOptions: {
drawerLabel: 'Demo Screen 1',
},
},
Screen2: {
//Title
screen: Screen2_StackNavigator,
navigationOptions: {
drawerLabel: 'Demo Screen 2',
},
},
Screen3: {
//Title
screen: Screen3_StackNavigator,
navigationOptions: {
drawerLabel: 'Demo Screen 3',
},
},
});
export default createAppContainer(DrawerNavigatorExample);
Now, the problem is I want to make another class as my default class and from that class I want to import App.js and then lauch the App.js class. But in the App.js class I already have one export-
export default createAppContainer(DrawerNavigatorExample);
And in React-native it doesn't allow me to export multiple modules.
So, if I want to Export the App.js file and use it inside the View of another class, then how I can do that?
You can only export one module as default.
you can use export only
export const AppRoute = createAppContainer(DrawerNavigatorExample);
to import that
import { AppRoute } from 'App.js';
I think you can export default your class like this:
import React, { Component } from 'react';
import { View, Image, TouchableOpacity } from 'react-native';
import {
createDrawerNavigator,
createStackNavigator,
createAppContainer,
} from 'react-navigation';
import Screen1 from './pages/Screen1';
import Screen2 from './pages/Screen2';
import Screen3 from './pages/Screen3';
class NavigationDrawerStructure extends Component {
toggleDrawer = () => {
this.props.navigationProps.toggleDrawer();
};
render() {
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity onPress={this.toggleDrawer.bind(this)}>
{/*Donute Button Image */}
<Image
source={require('./image/drawer.png')}
style={{ width: 25, height: 25, marginLeft: 5 }}
/>
</TouchableOpacity>
</View>
);
}
}
const FirstActivity_StackNavigator = createStackNavigator({
First: {
screen: Screen1,
navigationOptions: ({ navigation }) => ({
title: 'Demo Screen 1',
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
});
const Screen2_StackNavigator = createStackNavigator({
Second: {
screen: Screen2,
navigationOptions: ({ navigation }) => ({
title: 'Demo Screen 2',
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
});
const Screen3_StackNavigator = createStackNavigator({
Third: {
screen: Screen3,
navigationOptions: ({ navigation }) => ({
title: 'Demo Screen 3',
headerLeft: <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
});
export const DrawerNavigatorExample = createAppContainer({
Screen1: {
//Title
screen: FirstActivity_StackNavigator,
navigationOptions: {
drawerLabel: 'Demo Screen 1',
},
},
Screen2: {
//Title
screen: Screen2_StackNavigator,
navigationOptions: {
drawerLabel: 'Demo Screen 2',
},
},
Screen3: {
//Title
screen: Screen3_StackNavigator,
navigationOptions: {
drawerLabel: 'Demo Screen 3',
},
},
});
export default new NavigationDrawerStructure();
Than, you can import like this:
import { DrawerNavigatorExample }, NavigationDrawerStructure from './App.js';

Header title is empty in TabNavigation

Header title seems to not work as expected.
I already updated react-native and all other dependencies to their latest version and reviewed react-navigation documentation. Also I created a bug on github for this item.
Can you please take a look if I doing something wrong? I need to have header title set when i am using TabNavigation
const RootNavigator = createStackNavigator({
...publicScreens,
Private: {
screen: PrivateNavigator
}
}, publicScreensConfig);
const privateScreens = {
ContactList: {
screen: ContactList
},
Settings: {
screen: Settings
}
};
.....
export default createBottomTabNavigator( privateScreens, options );
import React, { Component } from 'react'
import { Text, View } from 'react-native'
import GlobalColors from '../../config/colors';
export default class Settings extends Component {
static navigationOptions = {
title: 'Settings',
headerStyle: {
backgroundColor: GlobalColors.grayDark,
},
headerTintColor: 'white',
headerTitleStyle: {
fontWeight: 'bold',
},
gesturesEnabled: false,
}
render() {
return (
<View>
<Text> Settigs </Text>
</View>
)
}
}
But I see empty header title in the header pane.
I want to see header text that come from navigation Options
Thanks to JinHoSo answer is here
const bottomTabNavigator = createBottomTabNavigator(...)
bottomTabNavigator.navigationOptions = ({navigation, screenProps}) => {
const childOptions = getActiveChildNavigationOptions(navigation, screenProps)
return {
title : childOptions.title,
headerLeft : childOptions.headerLeft,
headerRight: childOptions.headerRight,
}
}

Navigate in React-Native

I trying to navigate in react-native, this is my source
import React from 'react';
import { StackNavigator } from 'react-navigation';
import { Text, TouchableOpacity } from 'react-native';
import LoginForm from './components/LoginForm';
import EmployeeList from './components/EmployeeList';
import EmployeeCreate from './components/EmployeeCreate';
const AddButton = (param) => (
<TouchableOpacity onPress={() => console.log(param)}>
<Text style={styles.addButtonStyle}>Add</Text>
</TouchableOpacity>
);
const styles = {
addButtonStyle: {
fontSize: 18,
marginRight: 25,
color: '#007AFF'
},
headerTitleStyle: {
fontWeight: 'normal',
alignSelf: 'center',
marginLeft: 50
}
};
const RouterComponent = StackNavigator({
EmployeeList: {
screen: EmployeeList,
navigationOptions: {
title: 'Employee List',
headerTitleStyle: styles.headerTitleStyle,
headerLeft: null,
headerRight: AddButton()
}
},
EmployeeCreate: {
screen: EmployeeCreate,
navigationOptions: {
title: 'Employee Create'
}
},
Home: {
screen: LoginForm,
navigationOptions: {
title: 'Please, Log In',
headerTitleStyle: styles.headerTitleStyle
}
}
});
export default RouterComponent;
Actually what I need, it's in my const AddButton reach this.props.navigation.navigate('EmployeeCreate'); for me be able to navigate to EmployeeCreate from AddButton, but AddButton doesn't have any props. I'm tried to throw props as parameter in AddButton, but nothing good happen. Anybody know, how fix this issue?
In the EmployeeList component in the StackNavigator, you can define the navigationOptions as such:
navigationOptions: ({navigation}) =>
return {
title: 'Employee List',
headerTitleStyle: styles.headerTitleStyle,
headerLeft: null,
headerRight: AddButton(navigation)
}
Then in the AddButton component, you can already use the navigation.navigate function.

Categories