The component for route 'Main' must be a React component - react-native

I am new to React Native and implementing react-navigation to understand this concept but getting error.
I searched for it through different links as The component for route 'Feed' must be a React component and I changed import and export according to the answer of this question but same error is still there. My code as below,
MainScreenNavigation.js
import { createAppContainer, createSwitchNavigator, createStackNavigator } from "react-navigation";
import Splash from '../screens/Splash/Splash';
import Signin from '../screens/Signin/Signin';
// import HomeScreen from '../screens/Home/HomeScreen';
// import Profile from '../screens/Profile/Profile'
export const MainScreenNavigation = createAppContainer(createSwitchNavigator({
Splash: Splash,
Main: SigninNavigator,
}, {
initialRouteName: 'Splash'
},
)
);
const SigninNavigator = createSwitchNavigator({
Signin: Signin,
// Home: HomeNavigator,
}, {
initialRouteName: 'Signin'
},
);
// const HomeNavigator = createStackNavigator({
// Profile: Profile,
// HomeScreen: HomeScreen,
// },
// {
// initialRouteName: 'HomeScreen'
// }
// );
App.js
import React, {Component} from 'react';
import {MainScreenNavigation} from "./src/navigations/MainScreenNavigation";
class App extends Component {
render() {
return (
<MainScreenNavigation />
);
}
}
export default App;
Splash.js
import React from 'react';
import {ImageBackground, StatusBar, View, Text, TouchableOpacity} from 'react-native';
import { Logo } from '../../components/Logo';
import { styles } from './styles';
class Splash extends React.Component{
gotoSigninScreen = () => {
this.props.navigation.navigate("Main");
};
render(){
return(
<ImageBackground
source={require('../../assets/splash.png')}
style={styles.imageBackgroundStyle}>
<StatusBar backgroundColor='#3F91D6'
barStyle='light-content' />
<View style={styles.container}>
<View style={styles.upperBody}>
<View style={styles.containerInside}>
<Logo />
<Text style={styles.upperBodyText}>Track, Drive & Deliever</Text>
</View>
</View>
<View style={styles.lowerBody}>
<TouchableOpacity style={styles.buttonContainer}
onPress={() => navigate('Signin')}>
<Text style={styles.buttonText}>Get Started</Text>
</TouchableOpacity>
</View>
</View>
</ImageBackground>
)
}
}
export default Splash;
Signin.js
import React from 'react';
import {TouchableOpacity, Text, TextInput, View, KeyboardAvoidingView} from 'react-native';
import {styles} from './styles';
import {Logo} from "../../components/Logo";
import {hintColor} from "../../prefabs/colors";
class Signin extends React.Component {
gotoHomeScreen = () => {
this.props.navigation.navigate("Home");
};
render() {
return (
<KeyboardAvoidingView behavior="padding" style={styles.container}>
<Logo/>
<View style={styles.formContainer}>
<TextInput style={styles.input}
autoCapitalize="none"
onSubmitEditing={() => this.passwordInput.focus()}
autoCorrect={false}
keyboardType='email-address'
returnKeyType="next"
placeholder='Email'
placeholderTextColor={hintColor}/>
<TextInput style={styles.input}
returnKeyType="go"
ref={(input) => this.passwordInput = input}
placeholder='Password'
placeholderTextColor= {hintColor}
secureTextEntry/>
<TouchableOpacity style={styles.buttonContainer}
// onPress={this.gotoHomeScreen}
>
<Text style={styles.buttonText}>LOGIN</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
);
}
}
export default Signin;
Whats actually going wrong with this code and how to fix it?

I get rid of this error by changing my MainScreenNavigation.js as follows
MainScreenNavigation.js
import { createAppContainer, createSwitchNavigator, createStackNavigator } from "react-navigation";
import Splash from '../screens/Splash/Splash';
import Signin from '../screens/Signin/Signin';
import HomeScreen from '../screens/Home/HomeScreen';
import Profile from '../screens/Profile/Profile';
const HomeNavigator = createStackNavigator({
Profile: Profile,
HomeScreen: HomeScreen,
},
{
initialRouteName: 'HomeScreen'
}
);
const SigninNavigator = createSwitchNavigator({
Home: HomeNavigator,
Signin: Signin,
}, {
initialRouteName: 'Signin'
},
);
export const MainScreenNavigation = createAppContainer(createSwitchNavigator({
Main: SigninNavigator,
Splash: Splash,
}, {
initialRouteName: 'Splash'
},
)
);

Related

React Native Redux - Not showing updated state via different route

I'm writing a react-native app via expo and trying to implement redux. I'm not sure if I'm going about this completely the wrong way. I have a home page that has two sections, a search text box and an area with links to content pages. The content pages also contain the same search box component. I want to be able to pass the contents of the search box input to the content page so that the user doesn't need to enter this again (and will probably require access to this content further in the user journey)
My app.js looks like the below:
import React from 'react';
import 'react-native-gesture-handler';
import { createStackNavigator } from 'react-navigation-stack';
import { createAppContainer } from 'react-navigation';
import ContentPage from './pages/ContentPage.js';
import LogoTitle from './components/LogoTitle';
import EventsListPage from './pages/EventsListPage.js';
import EventPage from './pages/EventPage';
import VenuePage from './pages/VenuePage';
import HomeScreen from './pages/HomePage';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
const initialState ={
postcode:"abcefg"
}
const reducer = (state = initialState, action) => {
switch(action.type)
{
case 'SET_POSTCODE':
return {
postcode: action.text
}
default:
console.log("returning default state")
return state
}
}
const store = createStore(reducer);
const RootStack = createStackNavigator(
{
Home: HomeScreen,
ContentPage: ContentPage,
EventsListPage: EventsListPage,
EventPage: EventPage,
VenuePage: VenuePage
},
{
initialRouteName: 'Home',
defaultNavigationOptions: {
headerTitle: () => <LogoTitle />,
headerLeft: () => null,
headerStyle: {
backgroundColor: '#ADD8E6'
}
},
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<AppContainer />
</Provider>);
}
}
Homepage.js:
import React from 'react';
import { StyleSheet, View } from 'react-native';
import SearchBox from '../components/SearchBox'
import TypeDrillDownArea from '../components/TypeDrillDownArea'
import 'react-native-gesture-handler';
class HomeScreen extends React.Component {
constructor(props) {
super(props);
state = {
};
}
render() {
return (
<View style={styles.container}>
<SearchBox navigation={this.props.navigation} eventTypeId=''/>
<TypeDrillDownArea navigation={this.props.navigation} />
</View>
);
}
}
export default HomeScreen
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'stretch'
},
});
Relevant searchbox.js:
render() {
return (
<ImageBackground source={topperBackground} style={{width: '100%'}}>
<View>
<View style={styles.row}>
<View>
<TextInput
value={this.props.postcode}
autoCapitalize="characters"
style={styles.inputBox}
placeholder="Enter Postcode"
onChangeText={(e) => this.props.setPostcode(e)}
/>
</View>
<View>
<TouchableOpacity
disabled={this.state.locationDisabled}
onPress={() => {
this.props.navigation.navigate('EventsListPage', {
navigation: this.props.navigation,
eventTypeId: this.state.eventTypeId,
locLongitude: this.state.location.coords.longitude,
locLatitude: this.state.location.coords.latitude,
});
}}>
<Image
style={styles.locationPin}
source={locationPin}
/>
</TouchableOpacity>
</View>
</View>
<View style={styles.searchButtonArea}>
<TouchableOpacity
onPress={() => {
console.log("postcode is: " + this.state.postcode)
this.props.navigation.navigate('EventsListPage', {
eventTypeId: this.state.eventTypeId,
postcode: this.props.postcode,
});
}}>
<Text style={styles.searchButton}>SEARCH</Text>
</TouchableOpacity>
</View>
</View>
</ImageBackground>);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(SearchBox)
function mapStateToProps(state){
return {
postcode:state.postcode
}
}
function mapDispatchToProps(dispatch){
return{
setPostcode : (e) => dispatch({
type: 'SET_POSTCODE',
postcode : e
})
}
}
and finally relevant contentpage.js:
<View style={styles.container}>
<SearchBox navigation={this.props.navigation} eventTypeId={this.state.eventTypeId} />
<Image source={imageType(this.state.dataSource[0].eventTypeId)} style={styles.eventType} />
<Text style={styles.textToDisplay}>
{this.state.dataSource[0].eventTypeDescription}
</Text>
</View>
On load, the box is prepopulated with "abcefg" as expected. Changing the contents hits the reducer as expected. However when I navigate to a content page which loads the search box again the value is empty, regardless if I've changed the original state or not.
Am I missusing redux for what it's intended? Should I be doing this a different way?
For clarity below is the organisation of the components
In the reducer(), you are accessing action.text but in the dispatch(), you passed postcode value to postcode instead of text.

React native navigation: '_this2.props.navigation.navigate'

my App.js code
import React from 'react'
import { Icon } from 'react-native-elements'
import { StyleSheet, View, StatusBar } from 'react-native'
import { createAppContainer } from 'react-navigation'
import { createStackNavigator } from 'react-navigation-stack'
import HomeScreen from './screens/homeScreen'
import LoginScreen from './screens/loginScreen'
import SignupScreen from './screens/signup'
import Screen2 from './screens/screen2'
import Screen1 from './screens/screen1'
export default class App extends React.Component {
setLogged(){
this.setState({logged:true})
this.forceUpdate()
}
//change to false when want to enable login feature else true
state = {
logged: false,
}
render() {
if(this.state.logged){
return(
<View style={styles.container} >
<StatusBar hidden = {false}/>
<AppContainer />
</View>
)
}else{
return(
<View style={styles.container} >
<StatusBar hidden = {false}/>
<LoginScreen signup={()=>this.props.navigation.navigate('Signup')} success={()=>this.setLogged()} />
</View>
)
}
}
}
const styles = StyleSheet.create({
container: {
position: 'relative',
width: '100%',
height: '100%',
backgroundColor: '#000000',
},
})
const HomeAppContainer = createStackNavigator(
{
Home: {screen: HomeScreen},
Signup: { screen: SignupScreen },
Screen1: { screen: Screen1 },
Screen2: { screen: Screen2 },
},
{initialRouteName: "Home"},
);
const AppContainer = createAppContainer(HomeAppContainer)
and the login screen contains
import React, { Component } from 'react';
import { StyleSheet, View, Text, TouchableOpacity, TextInput, ToastAndroid } from 'react-native';
import Colors from '../constants/colors'
import GLOBAL from '../constants/global'
export default class LoginScreen extends Component {
state = {
email: '',
password: '',
}
login() {
if (userid == 'admin') {
ToastAndroid.show('Invalid email/password', ToastAndroid.SHORT);
} else {
GLOBAL.userid = userid;
this.props.success()
}
})
}
render() {
return (
<View style={styles.MainContainer}>
<Text style={styles.text}>Email:</Text>
<View style={styles.inputView}>
<TextInput
style={styles.inputs}
autoFocus
returnKeyType="next"
keyboardType="email-address"
onChangeText={(email) => { this.setState({ email: email }) }}
/>
</View>
<Text style={styles.text}>Password:</Text>
<View style={styles.inputView}>
<TextInput
style={styles.inputs}
secureTextEntry
onChangeText={(password) => { this.setState({password:password}) }}
/>
</View>
<View style={styles.buttonGroup}>
<TouchableOpacity
style={styles.button}
onPress={() => { this.login() }} >
<Text style={{ fontSize: 24 }}>Sign in</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={() => { this.props.signup() }}>
<Text style={{ fontSize:24 }}>Sign up</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
//my styles here
});
the error is as follows
TypeError: undefined is not an object(evaluating '_this2.props.navigation.navigate')
i am learning react-native and making this login screen.
The app will check if the user is already logged in. if not then he will be prompted login screen which will have sign up option.
If the user is already logged in the app will directly go to home screen where screen1 and screen2 is used in stack
Well, the navigation prop is only passed down the navigation tree. Your App component is not a navigation screen like Home/Signup... (it doesn't have a route)... So basically App is not part of a navigator, it's not created using createStackNavigator or the others.
So, in conclusion the navigation prop is not defined.
Basically, how to fix this: LoginScreen should also be a route inside a navigator, therefore the navigation prop will be defined. Your App component should not render anything besides the <AppContainer /> and further logic should be handled in the first screen defined in the routes, which in your case might be the LoginScreen. In there you'll check if the user is logged in or not and navigate accordingly.
There's a great guide on their website on how to accomplish authentication flow: https://reactnavigation.org/docs/en/4.x/auth-flow.html

Undefined is not an object for react navigation

I have two components for my project, and I have gone through all the steps for react navigation as follow:
// App.js
import React from 'react';
import Main from './app/componenets/Main'
import details from './app/componenets/details'
import { createStackNavigator, createAppContainer } from 'react-navigation'
const mainNavigator = createStackNavigator(
{
MainScreen: Main,
detailsScreen: details,
},
{
initialRouteName :'MainScreen'
}
);
const AppContainer = createAppContainer(mainNavigator);
export default class App extends React.Component{
render() {
return(
<AppContainer />
);
}
}
Then I have my Main.js which I have a method as follow:
import React from 'react';
import {
StyleSheet ,
Text,
View,
} from 'react-native'
import Note from './Note'
import detail from './details'
import { createStackNavigator, createAppContainer } from "react-navigation";
export default class Main extends React.Component {
static navigationOptions = {
title: 'To do list',
headerStyle: {
backgroundColor: '#f4511e',
},
};
constructor(props){
super(props);
this.state = {
noteArray: [],
noteText: ''
}
}
render() {
let notes = this.state.noteArray.map((val,key) => {
return <Note key={key} keyval={key} val={val}
goToDetailPage= {() => this.goToNoteDetail(key)} />
});
const { navigation } = this.props;
return(
<View style={styles.container}>
<View style={styles.footer}>
<TextInput
onChangeText={(noteText) => this.setState({noteText})}
style={styles.textInput}
placeholder='What is your next Task?'
placeholderTextColor='white'
underlineColorAndroid = 'transparent'
>
</TextInput>
</View>
<TouchableOpacity onPress={this.addNote.bind(this)} style={styles.addButton}>
<Text style={styles.addButtonText}> + </Text>
</TouchableOpacity>
</View>
);
}
//This method is declared in my Note.js
goToNoteDetail=(key)=>{
this.props.navigation.navigate('detailsScreen')
}
}
//Styles which I didn't post to be short in code here
But when I try to do the navigation I get this error:
'undefined is not and object(evaluating 'this.props.val.date')
Do I need to pass the props in a way? or should I do anything else? I am new to React native and confused!
in order to access this.props make arrow function or bind the function in constructor.
goToDetail=()=>{
this.props.navigation.navigate('detailsScreen')
}
Just remove createAppContainer
const AppContainer = mainNavigator;
and tell me what react-navigation that you work with

React Navigation Error this.props.navigation.navigat

I have two screens and I want to on click to move new screen using react navigation. but I got an error
this.props.navigation.navigate
here is my code. anyone knows what is an issue. I follow every step.
import React, {Component} from 'react';
import { AppRegistry, View, Text,StyleSheet, TextInput, Image, ScrollView, Button, TouchableOpacity} from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import SignUp from './SignUp';
class Login extends React.Component{
constructor(props){
super(props);
this.state = { text: 'Useless Placeholder' };
}
render(){
const {navigate} = this.props.navigation;
return(
<View>
<ScrollView showsVerticalScrollIndicator={false}>
<View style={styles.button}>
<TouchableOpacity>
<Text style={styles.buttonText}>SIGN IN</Text>
</TouchableOpacity>
</View>
<View style={styles.createAccount}>
<Text style={styles.createText}
onPress={() => this.props.navigation.navigate("Home")}
>Create new account</Text>
</View>
</View>
</ScrollView>
</View>
);
}
}
module.exports = Login;
const MainNavigator = createStackNavigator({
Home: {screen: SignUp}
});
export default createAppContainer(MainNavigator);
Your Login screen is not a part of your stack.
const MainNavigator = createStackNavigator({
Home: {screen: SignUp}
});
Just make a separate component of Login screen add it on the top of your stack then you are able to navigate.
like this
const MainNavigator = createStackNavigator({
Login:{screen:Login}
Home: {screen: SignUp}
});
Login.js
import React, {Component} from 'react';
import { AppRegistry, View, Text,StyleSheet, TextInput, Image, ScrollView, Button, TouchableOpacity} from 'react-native';
export default class Login extends React.Component{
constructor(props){
super(props);
this.state = { text: 'Useless Placeholder' };
}
render(){
const {navigate} = this.props.navigation;
return(
<View>
<ScrollView showsVerticalScrollIndicator={false}>
<View style={styles.button}>
<TouchableOpacity>
<Text style={styles.buttonText}>SIGN IN</Text>
</TouchableOpacity>
</View>
<View style={styles.createAccount}>
<Text style={styles.createText}
onPress={() => this.props.navigation.navigate("Home")}
>Create new account</Text>
</View>
</View>
</ScrollView>
</View>
);
}
MainNavigator.js
import React, {Component} from 'react';
import { AppRegistry, View, Text,StyleSheet, TextInput, Image, ScrollView, Button, TouchableOpacity} from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import SignUp from './SignUp';
import Login from './Login'
const MainNavigator = createStackNavigator({
Login: {screen:Login},
Home: {screen: SignUp}
});
export default createAppContainer(MainNavigator);
you haven't added your Login screen in stack
here like this
const MainNavigator = createStackNavigator({
Login : {screen: Login},
Home: {screen: SignUp}
});

React Navigation not working

I'm using Drawer Navigator from React Navigation but after creating the custom component, the navigation doesn't work. There is no issue regarding importing.
Here is the Code:-
import React, { Component } from 'react';
import {DrawerNavigator} from 'react-navigation';
import {StyleSheet,Text,View,ScrollView,Image,Dimensions,TouchableOpacity} from 'react-native';
import Ionicons from 'react-native-vector-icons/Ionicons';
import HomeScreen from './components/HomeScreen/HomeScreen';
import Home from './components/Home/Home';
import Sample from './Sample';
const{height,width}=Dimensions.get('window');
const CustomDrawer = (props) => {
return(
<View>
<View style={styles.list}>
<TouchableOpacity onPress={()=>this.props.navigation.navigate('Sample')}>
<View style={styles.listElements}>
<Ionicons name="md-home" size={25} color={'black'} style={styles.listIcons} />
<Text style={styles.listText}>Home</Text>
</View>
</TouchableOpacity>
</View>
</View>
)
}
const Drawer = DrawerNavigator({
HomeScreen: {
screen: HomeScreen
},
Home:{
screen:Home,
},
Sample:{
screen:Sample,
}
},
{
drawerWidth: 350,
contentComponent:CustomDrawer
});
export default class App1 extends React.Component {
render() {
return <Drawer />;
}
}
It throws an "Undefined is not an object (Evaluating '_this.props.navigation')" error clicking the view.