React Native: How to redirect - react-native

I'm new to React Native and I just don't get how react-navigation works. I've already spend multiple work days and tried different variants, but I don't even get the examples from https://reactnavigation.org/docs/intro/ to work.
My project is created with create-react-native-app AwesomeProject, like it's described on the React Native Docs.
So I went back to my last working point (without routing).
This is my File Structure:
root
- src
- - screens
- - - LoginScreen.js
- - - HomeScreen.js
- App.js
In my App.js I just perform an easy call:
import LoginScreen from './src/screens/LoginScreen';
export default LoginScreen;
This is a simplified version of my LoginScreen.js:
import React from 'react';
import {
StyleSheet,
Text,
View,
AppRegistry,
Button,
ReactNative,
} from 'react-native';
/**
* Actual View
*/
class LoginScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
// some values
}
}
render() {
return (
<View style={[styles.containerOne]}>/>
// Some Input fields
<Button
onPress={this.loginButtonOnPress.bind(this)}
title="Login"
style={[styles.loginButton]}
/>
</View>
);
}
loginButtonOnPress() {
// Validation with fetch
}
}
export default LoginScreen;
/**
* Style
*/
const styles = StyleSheet.create({
containerOne: {
marginTop: -160,
justifyContent: 'center',
flex: 1,
alignItems: 'center',
}
loginButton: {
color: 'blue',
marginTop: 10,
}
});
The LoginScreen.js should be the first displayed page. I want to load my HomeScreen.js file when loginbuttonOnPress get called. How am I supposed to do that? I've already found something like
const SimpleApp = StackNavigator({
Login: { screen: LoginScreen },
Home: { screen: HomeScreen },
});
But I don't get this to work, too.
I'm thankfull for every help I can get.

Press login button then go to HomeScreen.
render() {
return (
<View style={[styles.containerOne]}>/>
// Some Input fields
<Button
onPress={() => navigation.navigate('Home'))}
title="Login"
style={[styles.loginButton]}
/>
</View>
);
}
You can try it work
App.js
const SimpleApp = StackNavigator({
Login: { screen: LoginScreen },
Home: { screen: HomeScreen },
},{ swipeEnabled: false }
);
export default SimpleApp

Try this inside you function
loginButtonOnPress() {
this.props.navigation.navigate('Home')
}

Related

How to fix "Cannot read property 'navigate'of undefined"

I'm very new to React Native, right now I'm trying to build a Login component, once login succeed, I'd like to redirect the component from Login screen to the main screen. I'm using React Navigation and somehow it keeps showing me the error "Cannot read property 'navigate' of undefined".
Did I do something wrong or I just missed something? Very appreciate for any kind help!
I'm using Visual Studio Code-Insiders (v1.37.0)
npm -v:6.4.1
expo -V:2.21.2
react-navigation: ^3.11.0
The code very basic:
import React, { Component } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { Avatar, Button, Icon } from 'react-native-elements'
import * as t from 'tcomb-form-native'
import Router from '../config/router';
const Form = t.form.Form;
const PWD = '2';
const UME = 'J';
class Login extends Component {
constructor(props) {
super(props);
this.state = {
login: {}
};
this.LoginModel = t.struct({
un: t.String,
pwd: t.String,
rm: t.Boolean
});
this.LoginOptions = {
fields: {
un: {
label: 'User Name',
error: 'Please type your username'
},
pwd: {
label: 'Password',
password: true,
secureTextEntry: true,
error: 'Please type the password'
},
rm: {
label: 'Remember me'
}
}
}
}
onChange(form) {
this.state.login = form;
}
onSubmit() {
console.log(this.props); // will output an empty object! but how?
const { navigate } = this.props.navigation; // Here is where the error message captured and throw out!
const value = this.refs.form.getValue();
if (value.un === UME && value.pwd === PWD) {
alert('Welcome back, Jack');
// setTimeout(() => {
// navigate('Home');
// }, 300);
}
}
render() {
return (
<View style={styles.container}>
<View style={{ alignItems: "center", marginBottom: 30 }}>
<Avatar
size="xlarge"
icon={{ name: 'apple', color: 'black', type: 'font-awesome' }}
overlayContainerStyle={{ backgroundColor: 'white' }}
onPress={() => console.log("Works!")}
activeOpacity={0.7}
containerStyle={{ marginTop: 15 }}
/>
</View>
<Form
ref="form"
type={this.LoginModel}
value={this.state.login}
options={this.LoginOptions}
onChange={(f) => this.onChange(f)}
/>
<Button
icon={
<Icon
type='font-awesome'
name="user"
size={25}
color="white"
iconStyle={styles.icon}
/>
}
title="Login"
style={styles.btn}
onPress={()=>this.onSubmit()}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 80
},
icon: {
paddingRight: 10
},
btn: {
}
});
export default Login;
UPDATE:
This is the App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import LoginScreen from './src/screens/Login'
export default function App() {
return (
<LoginScreen />
);
}
Based on your code, you have yet created the navigation stack, just add a StackNavigator for your Login component should work
// Other imports
import { createStackNavigator, createAppContainer } from "react-navigation";
...
class Login extends Component {
....
}
const styles = StyleSheet.create({...});
const AppNavigator = createStackNavigator({
Login: {
screen: Login
}
});
export default createAppContainer(AppNavigator);
You can refer the react-navigation's document
However this is just a quick way of doing it, you may need to structure the navigation stack in separate file.
Using a arrow function might work:
onSubmit = () => {
console.log(this.props);
const { navigate } = this.props.navigation;
//...
}
The keyword 'this' refers to the function that calls it. But onSubmit has no props.
"ES5 introduced the bind() method to set the value of a function this regardless of how it's called, and ES2015 introduced arrow functions which don't provide their own this binding (it retains the this value of the enclosing lexical context)." You can read more about that in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
Always prefer using arrow functions to avoid this. :)
From the code i would assume that your are rendering LoginScreen inside your App.js.
Doing that, you are not putting LoginScreen inside any navigator, making this.props.navigation equal to undefined.

How to add splashscreen?

I want to add a splashscreen to my code before the HomeScreen comes.
This is my new Splashscreen.js file
import React from 'react';
import { StatusBar, View, Text, ActivityIndicator } from 'react-native';
import HomeScreen from './screens/HomeScreen.js';
export default class SplashScreen extends React.Component {
render() {
return(
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#34495e'}}>
<StatusBar backgroundColor="#2c3e50" barStyle="light-content" />
<Text style={{ color: 'white', fontSize: 18}}>WELCOME</Text>
<ActivityIndicator color={'white'} />
</View>,
);
}
}
This is my new App.js file
import React, {Component} from 'react';
import { Keyboard, Alert } from 'react-native';
import {createAppContainer, createStackNavigator} from 'react-navigation';
import HomeScreen from './screens/HomeScreen.js';
/** Importing navigator */
import AppDrawerNavigator from './drawerNavigator';
/** Redux **/
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import SplashScreen from './screens/SplashScreen.js';
const initialState = {
username: null,
password: null,
};
const reducer = (state=initialState, action) => {
if(action.type) {
console.log('NEW',action.name);
}
return {state, username: action.name, password: action.pass};
}
const store = createStore(reducer);
class App3 extends React.Component {
componentWillMount() {
this.state = {
view: <SplashScreen />
};
setTimeout(() => {
this.setState({
view: <HomeScreen />
})
}, 2000)
}
render() {
return (
// this.state.view,
<Provider store = {store}>
<AppContainer />
</Provider>
);
}
}
export default App3;
const AppStackNavigator = createStackNavigator(
{
Home: {
screen: HomeScreen
},
Welcome: {
screen: AppDrawerNavigator
}
},
{
initialRouteName: 'Home',
headerMode: "none",
}
);
const AppContainer = createAppContainer(AppStackNavigator);
If you want to check my other screens and files you can check this link.
I want to add the splashscreen file I created to my existing code without affecting the exisiting functionality. I want to achieve the following things:
Open application
Show splashscreen for a sec.
Go to login screen if not logged in before otherwise go to Welcomescreen directly from splashscreen
I would recommend you to take a look at Spencer Cali medium article. It covers adding a splash screen for RN apps step by step. How to Add a Splash Screen to a React Native App (iOS and Android)
For react-native you do not need to create file for splash screen.
just follow bellow package for splash screen i suggest you that is very good library with lots of users and yes i'm always prefer this library for splash screen.
you just need to create image for the splash screen whatever you want to show upon user on initial.
react-native-splash-screen
you may find all detail here and follow it step by step it will help you.
it always help for me!
Splash screen and loading screen are different. The splash screen is shown when application is open from termination status.
After that, some applications show loading screens for processing background logics as like checking user signin, get datas and so on.
In you case, you looks to show loading screen for authentication flows.
Use this ways.
React Navigation Auth flows
This flow is as below.
Show loading screen and check the user auth
navigate to another screen according to auth result.
if (loggedIn) { this.props.navigation.navigate('SignUpScreen') }
else { this.props.navigation.navigate('HomeScreen') }
Happy!
And if you want to use splash screen, not loading screen, I recommend to use rn-toolbox.

Load random screen w/ React Native Navigation

I'm trying to build an app in react native where you hit a button and it loads a random screen. Pretty simple, but I can't get the navigator working.
import React from 'react';
import {
AppRegistry,
Text,
View,
Button,
StyleSheet,
Image,
} from 'react-native';
import { StackNavigator } from 'react-navigation';
import Slide0 from './slides/0';
import Slide1 from './slides/1';
import Slide2 from './slides/2';
randomScreen = Math.floor(Math.random() * 2);
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
};
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<Image
source={require('./assets/icons/app-icon.png')}
/>
<Text style={{ marginTop: 100 }}>Welcome to Dementia Care Activities.</Text>
<Text style={{ marginTop: 100 }}>{randomScreen}</Text>
<Button
onPress={() => navigate('Slide0')}
title="Load Random Slide"
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
const SimpleAppNavigator = StackNavigator({
Home: { screen: HomeScreen },
Slide0: { screen: Slide0 }
});
const AppNavigation = () => (
<SimpleAppNavigator />
);
export default class App extends React.Component {
render() {
return (
<AppNavigation/>
);
}
}
So I'm trying to set randomScreen to a number, and that does work and I can see it in the , but I just cant figure out how to insert that number into
const SimpleAppNavigator = StackNavigator({
Home: { screen: HomeScreen },
Slide0: { screen: SlideINSERT-RANDOM-NUMBER }
});
You could just create a list of Screen objects. It may seem redundant since you are including integers to differentiate the Screen objects, but if you ever decide to change those object names to something different, the map will already have you covered. So something like:
const screens = [Screen0, Screen1]
Then:
const SimpleAppNavigator = StackNavigator({
Home: { screen: HomeScreen },
Slide0: { screen: screens[randomScreen] }
});

React Native navigation: undefined is not an object

I try to implement a navigation in React Native with react-navigation according to this tutorial, but I am facing the following error when launching the app:
undefined is not an object (Evaluating 'this.props.navigation.navigate')
render index.android.js:17:12
My index.android.js:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Button
} from 'react-native';
import {
StackNavigator,
} from 'react-navigation';
export default class Abc extends Component {
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Button
title="Go to List"
onPress={() =>
navigate('Liste')
}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
export class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
const { navigate } = this.props.navigation;
return (
<Button
title="Go to List"
onPress={() =>
navigate('Profile')
}
/>
);
}
}
export class Liste extends React.Component {
static navigationOptions = {
title: 'Liste',
};
render() {
const { navigate } = this.props.navigation;
return (
<Button
title="Liste"
/>
);
}
}
const App = StackNavigator({
Home: { screen: HomeScreen },
Liste: { screen: Liste },
});
AppRegistry.registerComponent('Abc', () => Abc);
Do you have any suggestions? Thank you!
I believe what you wanted to do is to register your App component in your AppRegistry instead of the Abc component.
The reason that you ran into this undefined is not an object (Evaluating 'this.props.navigation.navigate') is because the props.navigation is not available in your Abc component. If you look closely to the bottom of your code,
you have:
const App = StackNavigator({
Home: { screen: HomeScreen },
Liste: { screen: Liste },
});
AppRegistry.registerComponent('Abc', () => Abc);
So you have created a StackNavigator component, but you are not registering this component but instead you are registering the Abc component in the AppRegistry, and since Abc component is not any of the screen under your StackNavigator, it won't have access to the this.props.navigation thus you would run into the exception.
You don't have Profile screen.
If you want to go to Liste screen from HomeScreen use:
onPress={() => navigate('Liste')}
If you want to go to Profile screen then you need to make Profile Screen and add it on StackNavigator, example:
export class Profile extends React.Component {
static navigationOptions = {
title: 'Profile',
};
render() {
const { navigate } = this.props.navigation;
return (
<Button
title="Profile"
/>
);
}
}
const App = StackNavigator({
Home: { screen: HomeScreen },
Liste: { screen: Liste },
Profile: {screen: Profile},
});
almost 3 years since the original question was asked. I had the same problem and landed on this page.
react-navigation is v5 now. The problem I had was because 'navigation' was not passing to the child component.
After a bit more research I fixed the problem using this solution from here.
I need to pass the props to child component like this.
<GoToButton navigation={props.navigation} />
https://reactnavigation.org/docs/connecting-navigation-prop
Hopefully this helps to new comers like me.

Disable console log in react navigation

I'm using react navigation for my app development. When i run log-android, it keeps logging something like this.
Navigation Dispatch: Action: {...}, New State: {...}
which is from createNavigationContainer.js line 150.
I've run through github and document said it could be done by by setting onNavigationStateChange={null} on a top-level navigator.
How can i achieve this by setting onNavigationStateChange={null} and where should i set it?
I've try to set like below, but it the page will not be able to redirect to other page.
export default () => {
<App onNavigationStateChange={null} />
}
Below are my app.js code
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View } from 'react-native';
import { StackNavigator,DrawerNavigator } from 'react-navigation';
import DrawerContent from './components/drawer/drawerContent.js';
import News from './components/news/home.js';
const drawNavigation = DrawerNavigator(
{
Home : {
screen : News ,
navigationOptions : {
header : null
}
}
},
{
contentComponent: props => <DrawerContent {...props} />
}
)
const StackNavigation = StackNavigator({
Home : { screen : drawNavigation,
navigationOptions: {
header: null
}
}
});
export default StackNavigation;
This is my drawerContent.js
import React, {Component} from 'react'
import {View,Text, StyleSheet,
TouchableNativeFeedback,
TouchableOpacity,
TouchableHighlight
} from 'react-native'
import { DrawerItems, DrawerView } from 'react-navigation';
import Icon from 'react-native-vector-icons/Octicons';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
class DrawerContent extends Component {
constructor(props){
super(props);
console.log('DrawerContent|testtttttt');
}
render(){
return (
<View style={styles.container}>
<Text>Hi darren</Text>
<TouchableOpacity style={{ marginBottom:5 }} onPress={() => this.props.navigation.navigate('RegistrationScreen') } >
<View style={styles.nonIconButton}>
<Text style={{ color: 'black',fontSize: 13 }} >Sign Up</Text>
</View>
</TouchableOpacity>
<Text>Hi darren</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
export default DrawerContent;
First, make sure you are using the latest release of react-navigation as the comment noting that the fix was committed is fairly recent.
Based on your code example, to disable logging for all navigation state changes, you would want to replace this code:
export default StackNavigation;
with:
export default () => (
<StackNavigation onNavigationStateChange={null} />
);
as StackNavigation appears to be your root navigator.
React navigation is great, but this logging is really bad. Solution
const AppNavigator = StackNavigator(SomeAppRouteConfigs);
class App extends React.Component {
render() {
return (
<AppNavigator onNavigationStateChange={null} />
);
}
}