TypeError: undefined is not an object (evaluating '_this.props.navigation') in React Native - javascript

I'm trying to work with React Navigation using an external button component, to make styling it easier, but it gives me the TypeError: undefined is not an object (evaluating '_this.props.navigation') error when I try to pass the navigation. If I create the button on my home screen it works fine, but that clutters up my HomeScreen's stylesheet, and means I have to repeat code when I use the button elsewhere.
I have the stack navigation set up in my App.js, and again, it works fine when I'm not trying to pass the navigation as a prop.
Here's HomeScreen.js
import React from "react";
import {
ScrollView,
StyleSheet,
Text,
View,
AsyncStorage,
} from 'react-native';
import Heading from '../heading';
import Input from '../Input';
import Button from "../Button";
export const Home = ({navigation}) => (
<View style={styles.container}>
<ScrollView style={styles.content}>
<Heading />
</ScrollView>
<Button/>
</View>
)
And here's my Button.js
/* eslint-disable prettier/prettier */
import React from 'react';
import {
StyleSheet,
Text,
View,
TouchableHighlight
} from 'react-native';
import { useNavigation } from '#react-navigation/native';
function Button(){
const navigation = useNavigation()
return(
<View style={styles.buttonContainer}>
<TouchableHighlight
underlayColor='rgba(175, 47, 47, .75)'
activeOpacity={1.0}
style={styles.button}
onPress={() => {
navigation.navigate("New Medication");
}}>
<Text style={styles.submit}>
+
</Text>
</TouchableHighlight>
</View>
)
}
As far as I understand it, this should work just fine, so why is it saying that it's being passed as undefined?
UPDATE: Thanks to some suggestions I now have it to where it doesn't give an error, just does nothing.
Here's my App.js, with my navigation
const Stack = createStackNavigator();
function MyStack() {
return (
<Stack.Navigator
screenOptions={{
headerShown: false
}}>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="NewMedication" component={newMedScreen} />
</Stack.Navigator>
);
}
class App extends Component{
render(){
return(
<NavigationContainer>
<MyStack />
</NavigationContainer>
);
}
}
export default App;

I recommend you to create a const with screen name and reuse it everywhere to avoid such problem. You nave stack like this <Stack.Screen name="NewMedication" component={newMedScreen} /> , but try to navigate
navigation.navigate("New Medication").Of course this screen do not exist
const NEW_MEDICATION_SCREEN = 'NewMedication'
<Stack.Screen name={NEW_MEDICATION_SCREEN} component={newMedScreen} />
.....
onPress={() => navigation.navigate(NEW_MEDICATION_SCREEN)}>
and for make Button reusable use it like this
function Button({onPress}){
return(
<View style={styles.buttonContainer}>
<TouchableHighlight
underlayColor='rgba(175, 47, 47, .75)'
activeOpacity={1.0}
style={styles.button}
onPress={onPress}>
<Text style={styles.submit}>
+
</Text>
</TouchableHighlight>
</View>
)}
export const Home = ({navigation}) => (
<View style={styles.container}>
<ScrollView style={styles.content}>
<Heading />
</ScrollView>
<Button onPress={() => navigation.navigate(NEW_MEDICATION_SCREEN)}/>
</View>

Related

Passing parameters to routes

I am currently fiddling with some exercise code, from what i seen in https://reactnavigation.org/docs/params/
You should be able to pass more than 1 params with route
But i can't seem to do that .
I only manage to send 1 of the two params that i wanted to pass from Topping.js to Rasa.js
What am i possibly doing wrong ?
Any help is appreciated
Topping.js
export default function HalTopping({route,navigation}){
const { JenisMie } = route.params;
const TipeMie = JenisMie;
return(
<ScrollView>
<Text>itemId: {JSON.stringify(JenisMie)}</Text>
<View style={styles.container}>
<View style={styles.card}>
<View style={styles.card_header}>
<Text style={styles.title}> Telur Dadar </Text>
</View>
<View style={{alignItems : 'center', margin : 20}}>
<Image
style={{width: 300, height : 300}}
source={require('./Img/Dadar.jpg')}
/>
</View>
</View>
<View style={styles.card_footer}>
<Button
title="Pilih!"
color="#dc3545"
onPress={() => navigation.navigate('HalPedas', {JenisTopping: "Telur Dadar"})} />
</View>
</View>
</ScrollView>
)
};
Rasa.js
export default function HalPedas({route,navigation}){
const { JenisMie1 } = route.params;
const { JenisTopping } = route.params;
return(
<Text>itemId1: {JSON.stringify(JenisMie1)}</Text>
<Text>itemId2: {JSON.stringify(JenisTopping)}</Text>)
App.js
import * as React from 'react';
import { Button, View, Text } from 'react-native';
import { useNavigation, NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import HalTopping from './Topping';
import HalPedas from './Rasa';
import HalPesanan from './Pesanan';
const Stack = createNativeStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="HalTopping" component={HalTopping}/>
<Stack.Screen name="HalPedas" component={HalPedas}/>
<Stack.Screen name="HalPesanan" component={HalPesanan}/>
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
When you navigate to 'HalPedas' you are only passing through one parameter, 'JenisTopping'.
<View style={styles.card_footer}>
<Button
title="Pilih!"
color="#dc3545"
onPress={() => navigation.navigate('HalPedas', {JenisTopping: "Telur Dadar"})}
/>
</View>
You can add an additional parameter as seen below
<View style={styles.card_footer}>
<Button
title="Pilih!"
color="#dc3545"
onPress={() => navigation.navigate('HalPedas', {
JenisTopping: "Telur Dadar",
JennisMeil: "Something Else"
})}
/>
</View>

React native navigation not displaying stack screen

I'm using React Native Navigation dependency as route. But I have problem in the following code which appears to do nothing.
I'm trying to create 2 screens, one is login, the other is register (later on I will add button to move between them, right now even the default screen doesn't work).
App.JS
import React from 'react';
import { View, StatusBar, Text } from 'react-native';
import Login from './login.js';
export default function App() {
return (
<View>
<StatusBar barStyle="dark-content" hidden={false} backgroundColor="#ffffff" translucent={true}/>
<Login/>
</View>
);
}
Login.JS
import React from 'react';
import Register from './register.js';
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
function LoginScreen() {
return (
<View style={{ flex: 1, paddingTop: 100, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
const Stack = createStackNavigator();
function Login() {
return (
<View style={styles.container}>
<Text style={styles.logo}>My Title</Text>
<Text style={styles.slogan}>Welcome</Text>
<NavigationContainer>
<Stack.Navigator initialRouteName="Login">
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Register" component={Register} />
</Stack.Navigator>
</NavigationContainer>
</View>
);
}
export default Login;
By reading the docs that should work, but I can't understand what is wrong here.
I receive blank area in the stack screen area.
I have tried to replace Register component with function, didn't work either.
How can I display React Native Navigation stack screen correctly?
How about having the Navigation Container wrap the contents of App.js then you can leave the Stack navigator and screens in the Login component
The container around your navigation has a background-color, so remove all background-color around it and see again.

Using createStackNavigator from #react-navigation/stack, unable to render a stackscreen

Im using createStackNavigator from #react-navigation/stack and I'm trying to render a form page with Formik as one of my stackScreens, but it won't display the page. I'm getting no errors and I believe I have styled it correctly so I'm not sure how to proceed. The home page works so I know the methodology works.
StackNavigator.js
import * as React from 'react';
import { createStackNavigator } from '#react-navigation/stack';
import LinkScreen from "../screens/LinksScreen"
import HomeScreen from "../screens/HomeScreen"
import User from "../screens/User"
import Form from "../screens/Form"
import Info from "../screens/Info"
const Stack = createStackNavigator();
const HomeStackNavigator = () => {
return (
<Stack.Navigator>
<Stack.Screen name ="Home" component={HomeScreen} />
</Stack.Navigator>
)
}
// Settings page
const SettingStackNavigator = () => {
return (
<Stack.Navigator initialRouteName={'Settings'} >
<Stack.Screen name="Settings" component={LinkScreen} />
<Stack.Screen name="Profile" component={User} />
</Stack.Navigator>
);
}
// Form Page
const FormStackNavigator = () => {
return (
<Stack.Navigator>
<Stack.Screen name="Form" component={Form} />
</Stack.Navigator>
);
}
// Other page?
const InfoStackNavigator = () => {
return (
<Stack.Navigator>
<Stack.Screen name="Info" component={Info} />
</Stack.Navigator>
);
}
export { HomeStackNavigator, SettingStackNavigator, FormStackNavigator, InfoStackNavigator };
Form.js
import * as WebBrowser from 'expo-web-browser';
import * as React from 'react';
import { Button, Image, Platform, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { ScrollView, TextInput } from 'react-native-gesture-handler';
import styles from'./screenStyles'
import {Formik} from 'formik'
export default function Form(){
return(
<View style={styles.container}>
<Formik
initialValues={{Test1: '', Test2: '', Test3:''}}
onSubmit={(values)=>{
console.log(values);
}}
>
{(props)=>{
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder='Test1 Text'
onChangeText={props.handleChange('Test1')}
value={props.values.Test1}
/>
<TextInput
style={styles.input}
placeholder='Test2 Text'
onChangeText={props.handleChange('Test2')}
value={props.values.Test2}
/>
<TextInput
style={styles.input}
placeholder='Test3 Input'
onChangeText={props.handleChange('Test3')}
value={props.values.Test3}
/>
<Button title='Submit' color='blue' onPress={props.handleSubmit}/>
</View>
}}
</Formik>
</View>
);
}
The form page just comes up with the form header but no content.
As looking on to your provided snack you were passing formik properties in the right way but not returning that form so returning that form works.
here is the working code.
export default function Form(){
return(
<View style={styles.container}>
<Formik
initialValues={{Test1: '', Test2: '', Test3:''}}
onSubmit={(values)=>{
console.log(values);
}}
>
{formikProps => ( // here you need to return your form
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder='Test1 Text'
onChangeText={formikProps.handleChange('Test1')}
value={formikProps.values.Test1}
/>
<TextInput
style={styles.input}
placeholder='Test2 Text'
onChangeText={formikProps.handleChange('Test2')}
value={formikProps.values.Test2}
/>
<TextInput
style={styles.input}
placeholder='Test3 Input'
onChangeText={formikProps.handleChange('Test3')}
value={formikProps.values.Test3}
/>
<Button title='Submit' color='blue' onPress={formikProps.handleSubmit}/>
</View>
)}
</Formik>
</View>
);
}
Here is a link to working snack

React Native: undefined is not an object (evaluating 'props.navigation.navigate')

I'm learning React Native and by trying to run this code using Expo it gives me the Exception error:
undefined is not an object (evaluating 'props.navigation.navigate'), at line 17 on App.js (marked in the comment)
There are two files: App.js and Untitled1.js
App:
import { StyleSheet, Text, View, TextInput, TouchableOpacity } from 'react-native';
import 'react-native-gesture-handler';
import { NavigationContainer } from '#react-navigation/native';
function App(props) {
return (
<View style={styles.container}>
<Text style={styles.logo}>APPetito</Text>
<Text style={styles.loginText}>Welcome to our app!</Text>
<Text style={styles.loginText}>Choose what do you want to do</Text>
// [ THE FOLLOWING LINE CONTAINS THE ERROR ]
<TouchableOpacity onPress={() => props.navigation.navigate("Untitled1")} style={styles.loginBtn}>
<Text style={styles.loginText}>I eat food</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.loginBtn}>
<Text style={styles.loginText}>I sell food</Text>
</TouchableOpacity>
</View>
);
}
// here there are the const styles
export default App;
Untitled.js
import * as React from 'react';
import React, { Component } from "react";
import { StyleSheet, View, Text } from "react-native";
import Icon from "react-native-vector-icons/Entypo";
import { NavigationContainer } from '#react-navigation/native';
function Untitled1(props) {
return (
<View style={styles.container}>
<Icon name="check" style={styles.icon}></Icon>
<Text style={styles.itWorks}>It works!</Text>
</View>
);
}
// here there are the const styles
export default Untitled1;
What can I do to solve the problem?
I think the problem is that you didn't create a Stack navigator in the first place to navigate between screens. Refer to react navigation docs to know more here
According to the docs you have to implement the stack navigator such as:
import * as React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
function Home(props) {
return (
<View style={styles.container}>
<Text style={styles.logo}>APPetito</Text>
<Text style={styles.loginText}>Welcome to our app!</Text>
<Text style={styles.loginText}>Choose what do you want to do</Text>
<TouchableOpacity onPress={() => props.navigation.navigate("Untitled1")} style={styles.loginBtn}>
<Text style={styles.loginText}>I eat food</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.loginBtn}>
<Text style={styles.loginText}>I sell food</Text>
</TouchableOpacity>
</View>
);
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Untitled1" component={Untitled1} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
I have updated your code a little bit to help you understand the concept.

React native navigation in flatlist

I using the flatlist to display a list of data. I wish to pass the data into another pages, but i have no idea which kind of navigation I shd use.
import Routes from './src/Routes';
export default class App extends Component<Props> {
render() {
return (
<View style={styles.container}>
<StatusBar
backgroundColor="#1c313a"
arStyle="light-content"
/>
<Routes/>
</View>
);
}
}
import React, { Component } from 'react';
import {StyleSheet, View, StatusBar,Text} from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createDrawerNavigator } from '#react-navigation/drawer';
import HomeScreen from '../pages/HomeScreen'
import YourActivitiesScreen from '../pages/YourActivitiesScreen'
import YourFavouriteScreen from '../pages/YourFavouriteScreen'
const Drawer = createDrawerNavigator();
function MyDrawer() {
return (
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen
name="Home"
component={HomeScreen}
options={{ drawerLabel: 'Home' }}
/>
<Drawer.Screen
name="Your Activities"
component={YourActivitiesScreen}
options={{ drawerLabel: 'Your Activities' }}
/>
<Drawer.Screen
name="Your Favourite"
component={YourFavouriteScreen}
options={{ drawerLabel: 'Your Favourite' }}
/>
</Drawer.Navigator>
);
}
export default function SideMenu() {
return (
<NavigationContainer>
<MyDrawer />
</NavigationContainer>
);
}
import React, { Component } from 'react';
import {Router, Stack, Scene} from 'react-native-router-flux';
import Login from './pages/Login';
import Signup from './pages/Signup';
import SideMenu from './components/SideMenu'
export default class Routes extends Component {
render() {
return(
<Router>
<Stack key="root" hideNavBar>
<Scene key="login" component={Login} title="Login" initial/>
<Scene key="signup" component={Signup} title="Signup" />
<Scene key="home" component={SideMenu} title="HomeScreen" />
</Stack>
</Router>
);
}
}
import React, { Component } from 'react';
import {
StyleSheet,
View,
Text,
AsyncStorage,
TouchableOpacity,
FlatList,
Button,
} from 'react-native';
import DetailsScreen from './Details';
import { createDrawerNavigator, SafeAreaView } from 'react-navigation';
class HomeScreen extends Component{
constructor(props) {
super(props);
this.state = {
activitiesList: [],
}
};
renderItem = (item) => {
return (
<TouchableOpacity
onPress={() => {
console.log('test')
}}
>
<View style={styles.item}>
<Text style={styles.title}>{item.name}</Text>
</View>
</TouchableOpacity>
);
}
render(){
const listActivities = this.state.activitiesList
return (
<View>
<View style={styles.container}>
<Text style={styles.heading}>UPCOMING ACTIVITIES</Text>
</View>
<View>
<SafeAreaView>
<FlatList
data = {listActivities}
renderItem={({ item }) => this.renderItem(item)}
keyExtractor={item => item.id}
/>
</SafeAreaView>
</View>
</View>
)
}
}
I used the react-native-router-flux at the early part of system, which is login, signup and home. Now home display the flatlist, from the flatlist i have to make a onPress to navigate to another pages, the Actions in router-flux that i used before cannot work. Anyone have idea about it? or another better way navigate to to the details of flatlist?
First off, I'd refactor all the code to use just one kind of navigator (in this case, going for react-navigation). So, we will have your router-flux code combined with your
//Your routes screen
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
//... add missing imports
const Stack = createStackNavigator();
//this will be your old router-flux
const Root = () => {
return (
<Stack.Navigator>
<Stack.Screen name="login" component={Login} title="Login" initial/>
<Stack.Screen name="signup" component={Signup} title="Signup" />
<Stack.Screen name="home" component={SideMenu} title="HomeScreen" />
</Stack.Navigator>
)
}
const Drawer = () => {
return (
<Drawer.Screen
name="Home"
component={HomeScreen}
options={{ drawerLabel: 'Home' }}
/>
<Drawer.Screen
name="Your Activities"
component={YourActivitiesScreen}
options={{ drawerLabel: 'Your Activities' }}
/>
<Drawer.Screen
name="Your Favourite"
component={YourFavouriteScreen}
options={{ drawerLabel: 'Your Favourite' }}
/>
</Drawer.Navigator>
)
}
const AppContainer = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Root" component={Root} />
<Stack.Screen name="Drawer" component={Drawer} />
//import your Details screen to use inside component
<Stack.Screen name="Details" component={Details} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default AppContainer
You will wrap your App.js component with this AppContainer. What we just did was to nest the navigations, your Home will be reached first and your drawer will be all in the same. Also, there is one missing stack in your code that is the one for the Details.
Right after here you are going to use all the actions from react-navigation. All the screens will receive a navigation props. Once you want to navigate from your Root, you will call the navigation just like props.navigation.navigate("Home").
The same will apply to navigate to your Detail screen from the FlatList.
//Your Home Screen
import React, { Component } from 'react';
import {
StyleSheet,
View,
Text,
AsyncStorage,
TouchableOpacity,
FlatList,
Button,
SafeAreaView
} from 'react-native';
class HomeScreen extends Component{
constructor(props) {
super(props);
this.state = {
activitiesList: [],
}
};
renderItem = (item) => {
return (
<TouchableOpacity
onPress={() => {
props.navigation.navigate("Details", { data: item })
console.log('test')
}}
>
<View style={styles.item}>
<Text style={styles.title}>{item.name}</Text>
</View>
</TouchableOpacity>
);
}
render(){
const listActivities = this.state.activitiesList
return (
<View>
<View style={styles.container}>
<Text style={styles.heading}>UPCOMING ACTIVITIES</Text>
</View>
<View>
<SafeAreaView>
<FlatList
data = {listActivities}
renderItem={({ item }) => this.renderItem(item)}
keyExtractor={item => item.id}
/>
</SafeAreaView>
</View>
</View>
)
}
}
Just added the navigation action to the code above. You have to access the params object in your Details Screen
//Details Screen
class DetailsScreen extends React.Component {
render() {
const { routes } = this.props;
return (
<View>
//Your component
<Text>{routes.data.name}</Text>
</View>
);
}
}
Just a side note. If you have a problem when navigating to a nested stack you can navigate this way using params
navigation.navigate(<YourParent>, {
screen: <YourDesiredScreen>,
params: { <YourObject> },
});
I hope it helps, at least as a guide. I didn't tested it, that's why I asked you to upload your code to expo.
I use react-navigation and couldn't be happier. All the navigation needed can be done with a simple:
this.props.navigation.navigate('ScreenName', {param1: 'Hello', param2: 'World'})
and then, when on the screen desired, get the param:
const { param1, param2 } = this.props.route.params;
More details here.
And, of course, if using function components it is even easier.
This example is form my 1st react-native-expo project but I hope that it will help you.
Bottom code is for two stack screens where I have PlayersTab screen and Player so main focus is to access Player with parms from PlayersTab using react-navigation
Navigation is in props object all you need is to destructor it in component const PlayersList = ({ navigation }) => {//your code}
import { View, Text } from 'react-native';
import React from 'react';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import PlayersList from '../personal_data_screen/PlayersList';
import PersonalDataScreenPlayer from'../personal_data_screen/PersonalDataScreenPlayer';
const Stack = createNativeStackNavigator();
const PersonalPlayerDataNavigator = ({ loginDataObject }) => {
return (
<Stack.Navigator>
<Stack.Screen options={{ headerShown: false }} name='PlayersTab'>
{(props) => (
<PlayersList {...props} loginDataObject={loginDataObject} />
)}
</Stack.Screen>
<Stack.Screen options={{ headerShown: false }} name='Player'>
{(props) => <PersonalDataScreenPlayer {...props} />}
</Stack.Screen>
</Stack.Navigator>
);
};
export default PersonalPlayerDataNavigator;
FlatList witch is in PlayersTab looks like this
<FlatList
data={Object.keys(friendList.data)}
renderItem={renderItem}
keyExtractor={keyExtractor}
navigation={navigation}
/>
const renderItem = ({ item }) => (
<Item
navigation={navigation}
account_id={friendList.data[item].account_id}
nickname={friendList.data[item].nickname}
/>
const Item = ({ nickname, account_id, navigation }) => (
<TouchableOpacity
onPress={() => navigation.navigate('Player', { account_id: account_id })}>
<View style={styles.itemView}>
<Text style={styles.playerNicknameText}>{nickname}</Text>
</View>
</TouchableOpacity>
And code for Player screen
import React from 'react';
import { View, Text } from 'react-native';
const PersonalDataScreenPlayer = ({ route }) => {
return (
<View
style={{
flex: 1,
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
}}>
<Text>{route.params.account_id}</Text>
</View>
);
};
export default PersonalDataScreenPlayer;

Categories