Trouble passing down this.props.navigation to child components - react-native

I am having a little trouble accessing this.props.navigation.navigate in child pages within ViewPager. I have a page where there's a button called "Details" and upon clicking the button it should open up a new separate view (like a new Intent Activity).
Structure is:
Login page -> tap on "login" button -> opens MainPage having a custom CustomBottomNavigationBar with ViewPager component which takes {Object} of 5 different pages and renders them like:
In the root App.js I've already defined this configuration:
// App.js
import MainPage from './views/mainpage';
import PageOne from './views/pageoneview';
import PageTwo from './views/pagetwoview';
import PageOneDetailView from './views/PageOneDetailView';
const MainNavigator = createStackNavigator({
Home: {screen: MainPage},
PageOne: {screen: PageOne},
PageTwo: {screen: PageTwo},
PageOneDetailView: {screen: PageOneDetailView}
},
{
headerMode: 'none',
navigationOptions: {
headerVisible: false,
}
});
// mainpage.js
import React, { Component } from 'react';
import {
StyleSheet,
Image,
View,
TouchableOpacity,
ToastAndroid
} from 'react-native';
import PageOne from './homepages/pageoneview';
import PageTwo from './homepages/pagetwoview';
import CustomBottomNavigationBar from './../components/CustomBottomNavigationBar';
export default MainPage extends Component {
constructor(props) {
super(props);
}
screens = () => {
return {
p1: {page: <PageOne/>},
p2: {page: <PageTwo/>}
}
}
render() {
return (
<CustomBottomNavigationBar
screensets={this.screens()}
/>
);
}
}
Now in PageOne.js there is a button called "Details" and on tapping, it must open a new PageOneDetail.js
// pageoneview.js
import React, { Component } from 'react';
import {
StyleSheet,
Image,
View,
TouchableOpacity,
ToastAndroid
} from 'react-native';
import PageOneDetail from './homepages/PageOneDetailView';
export default PageOne extends Component {
constructor(props) {
super(props);
}
OpenView = (navigateObject, whichScreen) => {
navigateObject(whichScreen);
}
render() {
const {navigate} = this.props.navigation;
return (
<View style={{ flex: 1, alignSelf: 'flex-end' }}>
<TouchableOpacity onPress={() => this.OpenView(navigate, 'PageOneDetailView')}>
<Text> Details </Text>
</TouchableOpacity>
</View>
);
}
}
The error I get when I land on the MainPage is: undefined is not an object this.props.navigation.navigate when mainpage.js tries to load pageoneview.js
Please help me understanding how to fix this issue which I have been facing whole day.
Thanks.

The navigation prop is only accessible to screens, not children of those screens. You can pass down the navigation from the parent or use withNavigation HOC or useNavigation hook from react-navigation-hooks to access it everywhere.

Related

Navigator Trouble

Good afternoon, actually i m keeping error while try to navigate.
This is my App.js
import { createStackNavigator, createAppContainer } from "react-navigation";
import Login from './src/Login';
import NuovoAccount from './src/NuovoAccount';
import HomePage from './src/HomePage';
import Lista_Sveglie from './src/Lista_Sveglie';
import NuovoAccount_2 from './src/NuovoAccount_2';
import Nuova_sveglia from './src/Nuova_sveglia';
import ScreenSveglia from './src/ScreenSveglia';
import Registra from './src/Registra';
import temp from './src/temp';
import Account from './src/Menu/Account';
import ElencoUtenti from './src/Menu/ElencoUtenti';
import MenuImpostazioni from './src/Menu/MenuImpostazioni';
import SelUtenteDest from './src/Menu/SelUtenteDest'
import Accedi from './src/Accedi'
import Landing from './Landing'
const AppNavigator = createStackNavigator(
{
Home: Landing,
Accedi : Accedi ,
Login: Login,
NuovoAccount: NuovoAccount,
HomePage: HomePage,
Lista_Sveglie: Lista_Sveglie,
NuovoAccount_2: NuovoAccount_2,
Nuova_sveglia: Nuova_sveglia,
ScreenSveglia: ScreenSveglia,
Registra: Registra,
temp: temp,
MenuImpostazioni: MenuImpostazioni,
ElencoUtenti: ElencoUtenti,
Account: Account,
SelUtenteDest: SelUtenteDest,
},
{
initialRouteName: "Home",
defaultNavigationOptions: {
headerTintColor: '#ccc',
headerStyle: {
borderBottomWidth: 4,
borderBottomColor: '#80ba27',
backgroundColor: '#364054',
},
headerTitleStyle: {
textAlign: 'center',
flex: 1
},
}
}
);
export default createAppContainer(AppNavigator)
and here my Landing.js
import React, { Component } from 'react';
import { StyleSheet, Text, View, Alert, Button } from 'react-native';
import * as firebase from 'firebase';
import HomePage from './src/HomePage';
import Accedi from './src/Accedi'
import { createStackNavigator, createAppContainer } from "react-navigation";
export default class Landing extends Component {
constructor() {
super();
this.state = {
loggedIn: false,
}
}
componentWillMount() {
console.log("QUI ENTRA")
---some firebase config ...
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.setState({ loggedIn: true })
} else {
this.setState({ loggedIn: false })
}
})
}
render(){
if (this.state.loggedIn){
return <HomePage/>
}else{
return <Accedi/>
}
}
}
Here my HomePage
<View>
<Text
onPress={() => this.props.navigation.navigate('MenuImpostazioni')}
style={style.footer_text_icone}>Configura Impostazioni</Text>
</View>
Can anyone tell me how to fix it and explain why this error ?
from documentation i saw this.props. is created on createnavigator function
"undefined is not an object - this.prop.navigation.navigate"
The problem here is that your HomePage component isn't a direct child of your stackNavigator. You need to pass it trough props to your child component doing:
render(){
if (this.state.loggedIn){
return <HomePage navigation={this.props.navigation}/>
}else{
return <Accedi/>
}
}
Inside the render function of your Landing.js
Then your child component will have access to it.
This is happening because you are using the same component, both as screen that as child component.
{
Home: Landing, //Here (as child)
Accedi : Accedi ,
Login: Login,
NuovoAccount: NuovoAccount,
HomePage: HomePage, //Here
Lista_Sveglie: Lista_Sveglie,
NuovoAccount_2: NuovoAccount_2,
Nuova_sveglia: Nuova_sveglia,
ScreenSveglia: ScreenSveglia,
Registra: Registra,
temp: temp,
MenuImpostazioni: MenuImpostazioni,
ElencoUtenti: ElencoUtenti,
Account: Account,
SelUtenteDest: SelUtenteDest,
}
react-navigation doesn't give access to navigation to a component just because it has been declared inside of it. By doing that if/else you are actually creating a whole new instance of that same component, with the only difference that it do not have access to this.props.navigation.
Landing.js isn't a screen that is defined within your stack navigator, so it does not have access to this.props.navigation.
If you don't want Landing.js within the stack navigator, you can follow this tutorial to use navigate and other navigation actions from any component: https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html

Undefined is not an object (Evaluating this.props.navigation.navigate) in reactnative

Good day.
I tried navigating to another page using reactnative navigation but it is displaying "Undefined is not an object (Evaluating this.props.navigation.navigate) in reactnative"
This is my code
import React, { Component } from 'react';
import {Text, View, Image, Alert} from 'react-native';
import { Icon, Button, List, ListItem, Left, Thumbnail, Body, Right } from 'native-base';
import {styles} from '../../../css/Designs';
import OptionsMenu from "react-native-options-menu";
const myIcon = (<Icon name='more' style={{fontSize:30,color:'#000'}}/>);
export class TheStudent extends Component {
constructor(props) {
super(props);
};
editItem = (student) => {
this.props.navigation.navigate('AllStudents');
}
deleteItem = (student) => {
Alert.alert(
'',
'Delete student?',
[
{
text: 'No',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel',
},
{
text: 'Yes',
onPress: () => this.deleteTheItem(student)
},
],
{cancelable: false},
);
}
deleteTheItem = (student) => {
alert(student);
}
render() {
return(
<List>
<ListItem avatar>
<Left>
<Thumbnail source={require('../../../img/male_avatar.png')} />
</Left>
<Body>
<Text style={styles.userName}>{this.props.surname} {this.props.firstname} {this.props.middlename} </Text>
<Text>{this.props.matric} {this.props.level}L {this.props.phone}</Text>
</Body>
<Right>
<OptionsMenu
customButton={myIcon}
options={["Edit", "Delete"]}
actions={[this.editItem.bind(this,this.props.id), this.deleteItem.bind(this,this.props.id)]}/>
</Right>
</ListItem>
</List>
);
}
}
I have been stucked in this for hours and I have tried all the other links I saw on this issue, but all to no avail.
I will be glad if you can be of help.
Thanks.
You should wrap your component with the HOC withNavigation then the prop will be available in the component, try something like this:
import { withNavigation } from 'react-navigation';
class TheStudent extends Component {
....
}
export withNavigation(TheStudent)
This is one solution which #Rachid Rhafour mentioned in his answer.
You can export your component withNavigation which can import from react-navigation.
import { withNavigation } from 'react-navigation';
class YourClassName extends Component {
}
export withNavigation(YourClassName)
Another approach is you can make route file by which you can navigate to any component file without any trouble.
example:
if there is two or three component to navigate or from navigate you should maintain that route by route file.
import React from "react";
import { createStackNavigator, createAppContainer } from "react-navigation";
import ScreenOne from "./ScreenOne";
import ScreenTwo from "./ScreenTwo";
const AppNavigator = createStackNavigator({
Home: {
screen: ScreenOne
},
Profile: {
screen: ScreenTwo
}
});
export default createAppContainer(AppNavigator);

invariant violation element type is invalid expected a string react native [duplicate]

This question already has answers here:
createStackNavigation invariant violation element type is invalid expected a string
(2 answers)
Closed 4 years ago.
So this is my first application inside react-native and I'm running into the following error.
I've tried working on this bug for the past few days but haven't had much luck.
Below is a copy of my MainNavigator.js:
import DlLoading_2 from "./src/screens/DlLoading_2";
import DlMain from "./src/screens/DlMain";
import { createStackNavigator, createAppContainer } from "react-
navigation";
const MainNavigator = createStackNavigator({
DlLoading_2: {
screen: DlLoading_2
},
DlMain: {
screen: DlMain
}
},
{
headerMode: "none"
}
);
export default createAppContainer(MainNavigator);
render() ;
return (
< MainNavigator />
) ;
And here is a copy of my opening page:
import React, { Component } from "react";
import { Center } from "#builderx/utils";
import { View, StyleSheet, Image, Text } from "react-native";
import { createAppContainer } from 'react-navigation';
import { MainNavigation } from '../screens/MainNavigator';
import { TouchableHighlight } from 'react-native'
import { AppContainer } from "../screens/MainNavigator"
const AppContainer = createAppContainer(MainNavigation);
export default class DlLoading_2 extends Component {
render() {
return (
<AppContainer/>
<View style={styles.root}>
<Center />
<TouchableHighlight onPress={() =>
this.navigation.navigate('DlMain')}/>
<Image style={styles.blueDisk} source= .
{require('../assets/ComponentTMP_0-image.jpg')}/>
<TouchableHighlight/>
<Center horizontal>
<Image
source={require("../assets/ComponentTMP_0-
image2.png")}
style={styles.dlLogo}
/>
</Center>
<Center horizontal>
<Text style={styles.text}>TRANSINDENTAL
MEDITATION</Text>
</Center>
<AppContainer/>
</View>
)
}
}
Any help on this error would be greatly appreciated! Thanks in advance.
There are few things going wrong in this. Let's take a look each file in turn
MainNavigation.js
You've set up your MainNavigator correctly however you don't set up the AppContainer that way.
This is how I would set up your MainNavigation.js
import Screen1 from './Screen1';
import Screen2 from './Screen2';
import { createStackNavigator, createAppContainer } from 'react-navigation';
const screens = {
Screen1: {
screen: Screen1
},
Screen2: {
screen: Screen2
}
}
const config = {
headerMode: 'none',
initialRouteName: 'Screen1'
}
const MainNavigator = createStackNavigator(screens, config);
export default createAppContainer(MainNavigator);
I prefer to separate everything out so that it is easy to see what everything is. The createAppContainer just wraps the MainNavigator you don't need to set a render function like you have done, as it is not being used and may lead to code errors.
In the options for the MainNavigator you can set your initalRouteName this is where the app will open on. If you want to open it on Screen2 set it accordingly, if you don't set it it will default to the first one in the list.
App.js
You have put in your AppContainer but then you have this <View> underneath it that is comprised of many things, including another AppContainer, where many of the tags are not closed properly.
I think that what is in the View should be on another screen in your MainNavigator, with that screen set as your initialRouteName.
This is how I would setup the App.js, you don't really need much more here.
import React, {Component} from 'react';
import AppContainer from './MainNavigation';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<AppContainer />
)
}
}
Here is a snack that allows you to navigate from Screen1 to Screen2 and back
https://snack.expo.io/r1FqD8VX4
Closing tags
When you open tags for a component, like View they are opened like this
<View>
When you close the tags for that View they are closed like this
</View>
Anything that is contained between those tags are called that component's children, and are accessed inside that component by this.props.children.
Not all components need to take children, like the Button component. It is opened and closed with the one tag like so
<Button onPress={} title={'title'} />
If you are looking at using TouchableHighlight this is how you would write the code so that it wraps your Image correctly
<TouchableHighlight onPress={() => this.props.navigation.navigate('DlMain')}>
<Image style={styles.blueDisk} source={require('../assets/ComponentTMP_0-image.jpg')}/>
</TouchableHighlight>

How to navigate to another activity when click on listitem

How to navigate one page to another in react native. Here I want to navigate to my activity to another activity, When i click on list item this will navigate to another page You can check my code below
import React, {Component} from 'react';
import { StyleSheet, View, AppRegistry,} from 'react-native';
import { List, ListItem, Icon, Text } from 'native-base';
import { StackNavigator } from 'react-navigation';
import Adjective from './Topic/Adjective';
class BasicFlatList extends Component {
onSourcesSetting = () => {
this.props.navigation.navigate('Adj');
}
render(){
return(
<List>
<ListItem
button
noBorder
onPress={() => this.onSourcesSetting}>
<Text>Adjective</Text>
</ListItem>
</List>
);
}
}
const App = StackNavigator({
Adj: Adjective,
});
export default BasicFlatList;
You can create a new screen(component) and pass the name of that route and other required parameters to the function.
import React, {Component} from 'react';
import { StyleSheet, View, AppRegistry,} from 'react-native';
import { List, ListItem, Icon, Text } from 'native-base';
import { StackNavigator } from 'react-navigation';
import Adjective from './Topic/Adjective';
class BasicFlatList extends Component {
onSourcesSetting = () => {
this.props.navigation.navigate('AdjDetail', {
// require params(maybe adj id)
});
}
render(){
return(
<List>
<ListItem
button
noBorder
onPress={() => this.onSourcesSetting}>
<Text>Adjective</Text>
</ListItem>
</List>
);
}
}
class AdjectiveDetail extends React.Component {
render() {
console.log("props", this.props);
return null;
}
}
const App = StackNavigator({
Adj: Adjective,
AdjDetail: AdjectionDetail
});
export default BasicFlatList;
From the code i guess you are using react-navigation. You can go through the documentation for more details
P.S: react-native creates a single activity and entire app is run inside the single activity, there is no such thing as navigate from one activity to another like in android.

undefined is not an object this.props

I try to use navigation between screen in my RN app. This is my code :
INDEX.ANDROID.JS :
import React, { Component } from 'react';
import {
AppRegistry,
Text,
View ,
Button
} from 'react-native';
import {StackNavigator} from 'react-navigation';
import Login from './app/components/Todo';
const SimpleApp = StackNavigator({
Login: { screen: Todo },
});
export default class aap extends Component {
static navigationOptions = { title: 'Welcome', };
render() {
const { navigate } = this.props.navigation;
return (
<Button onPress ={() => navigate('Todo') } title="go"/>
);
}
}
AppRegistry.registerComponent('aap', () => aap);
here is the code of the second screen TODO.JS
import React, { Component } from 'react';
import {
AppRegistry,
Text,
View ,
Button
} from 'react-native';
export default class Todo extends Component {
render() {
return (
<View>
<Text>
Here is my text
</Text>
</View>
);
}
}
When running my code i get an error : undefined is not an object this.props.naviagtion.
Any help is appreciated
You are not using StackNavigator correctly.
Like #xght said, you should be registering SimpleApp instead of aap. Also, you should be using aap as the initial route to your StackNavigator SimpleApp.
This should look something like this:
import React, { Component } from 'react';
import {
AppRegistry,
Text,
View ,
Button
} from 'react-native';
import {StackNavigator} from 'react-navigation';
import Todo from './app/components/Todo';
class aap extends Component {
static navigationOptions = { title: 'Welcome', };
render() {
const { navigate } = this.props.navigation;
return (
<Button onPress ={() => navigate('Todo') } title="go"/>
);
}
}
const SimpleApp = StackNavigator({
Login: { screen: aap },
Todo: { screen: Todo },
});
AppRegistry.registerComponent('aap', () => SimpleApp);
You registered the wrong component, so the navigator SimpleApp doesn't pass the navigation prop to your component.
Replace
AppRegistry.registerComponent('aap', () => aap); by:
AppRegistry.registerComponent('aap', () => SimpleApp);
And also you forgot to add your aap component in SimpleApp routes. And your import Login from './app/components/Todo';is wrong: Login is the name of the route in SimpleApp, and Todo is the name of the component, so you need to replace it by import Todo...