Unable to move to required screen using react-navigation? - react-native

I want to move to a different screen when I have some AsyncStorage item for authFlow but when I am going to the next screen and construction is calling out the function it is not moving to the next screen.
I tried to use the basic method this.props.navigation.navigate('navigator_name'), but i think it's not moving as blank screen is appearing.
App.js
------
import React from 'react';
import { StyleSheet, View, Text } from 'react-native';
import { createSwitchNavigator, createAppContainer, } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import AuthLoadingScreen from './screens/auth-loading-screen';
import WelcomeScreen from './screens/welcomeScreen';
import AppHomeScreen from './screens/app-home-screen';
const AuthStackNavigator = createStackNavigator({
welcome: WelcomeScreen
})
// export default
const TestContainer = createAppContainer(createSwitchNavigator({
AuthLoading: AuthLoadingScreen,
Auth: AuthStackNavigator,
App: AppHomeScreen,
},
{
initialRouteName: 'AuthLoading',
}
))
export default class App extends React.Component {
constructor () {
super()
this.state = {
loggedIn: 'false',
}
}
render() {
return(
<View style={styles.container}>
<TestContainer />
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
auth-loading-screen
-------------------
import React, { Component } from 'react';
import { View, Text, StyleSheet, ActivityIndicator, AsyncStorage } from 'react-native';
export default class AuthLoadingScreen extends Component {
constructor (props) {
super(props);
console.log('calling _loadApp')
this._loadApp();
}
_loadApp = async() => {
const userToken = await AsyncStorage.getItem('userToken');
console.log('getting value of token ', userToken, JSON.stringify(this.props.navigation.actions))
this.props.navigation.navigate(userToken ? 'App' : 'Auth')
}
render() {
return (
<View style={styles.container}>
<ActivityIndicator />
</View>
)
}
}
const styles = StyleSheet.create ({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
})
welcomeScreen
-------------
import React, { Component } from 'react';
import { View, Text, StyleSheet, Button} from 'react-native';
export default class WelcomeScreen extends Component {
constructor (props) {
super(props);
}
render() {
return (
<View style={styles.container}>
<Text>Welcome</Text>
</View>
)
}
}
const styles = StyleSheet.create ({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
})
The screen should directly move to the welcomeScreen as item is not set through AsynStorage

Your function is asynchronous. However, the constructor cannot execute the asynchronous function. Therefore, you should change the position of executing the function.
async componentDidMount() {
await this._loadApp();
}

Related

Missing header bar on a simple combination react-navigation

I wanted to try the MaterialBottomTabNavigator option in react-navigation. Unfortunately, it seems that the top bar is never displayed, although it should be according to the documentation.
import React from "React";
import { Text, View } from "react-native";
import { createAppContainer } from "react-navigation";
import { createMaterialBottomTabNavigator } from "react-navigation-material-bottom-tabs";
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Home Screen</Text>
</View>
);
}
}
export default createAppContainer(createMaterialBottomTabNavigator(
{
S1: {
screen: HomeScreen,
},
S2: {
screen: HomeScreen,
},
}
),
);
Is there something obvious I've been missing?
"createMaterialBottomTabNavigator" does not have header bar by default but "createStackNavigator" has header bar
You can try this code
import React from "React";
import { Text, View } from "react-native";
import { createAppContainer, createStackNavigator } from "react-navigation";
import { createMaterialBottomTabNavigator } from "react-navigation-material-bottom-tabs";
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Home Screen</Text>
</View>
);
}
}
const Tab1 = createStackNavigator({
S1: {
screen: HomeScreen
}
});
const Tab2 = createStackNavigator({
S2: {
screen: HomeScreen
}
});
export default createAppContainer(
createMaterialBottomTabNavigator({
Tab1,
Tab2
})
);
App Preview

Error: undefined is not an object (evaluating 'this.props.navigation.navigate')

I have created a separate route file and when I am trying to navigate between screens with the help of these routes with react-navigation using stackNavigator I am getting this error I have already tried other solutions available on Stack overflow but none of the answers solve my problem here is my code.
This is my Route.js file
import { createAppContainer, createStackNavigator } from 'react-navigation';
import Login from './screens/Login';
import Register from './screens/Register';
import Start from './screens/Start';
const AppNavigator = createStackNavigator({
Home: {
screen: Start,
},
LoginScreen: {
screen: Login,
},
RegisterScreen: {
screen: Register,
},
}, {
initialRouteName: 'Home',
navigationOptions: {
header: null
}
});
export default createAppContainer(AppNavigator);
And this is my component where I am trying to navigate
import React,{ Component } from 'react';
import { StyleSheet, View, KeyboardAvoidingView,Text } from 'react-native';
import NewButtons from './NewButtons';
import Logo from './Logo';
export default class Start extends Component{
constructor () {
super();
}
loginPress = () => {
this.props.navigation.navigate('LoginScreen');
}
registerPress = () => {
this.props.navigation.navigate('RegisterScreen');
}
render(){
return(
<KeyboardAvoidingView behavior='padding' style={styles.wrapper}>
<View style={styles.logoContainer}>
<Logo/>
<Text style={styles.mainHead}>Welcome to Food Zone</Text>
<Text style={{margin: 10, textAlign:'center'}}>Check out our menus, order food and make reservations{"\n"}{"\n"}</Text>
<NewButtons text="Login"
onPress={this.loginPress}/>
<NewButtons text="Register"
onPress={this.registerPress}/>
</View>
</KeyboardAvoidingView>
);
}
}
const styles = StyleSheet.create({
logoContainer: {
alignItems: 'center',
},
mainHead: {
fontFamily: 'PatuaOne',
color: '#ff9900',
fontSize: 28,
marginTop: -50,
},
})
And this in my button component
import React,{ Component } from 'react';
import { StyleSheet, View,Dimensions } from 'react-native';
import { Button, Text } from 'native-base';
const {width:WIDTH} = Dimensions.get('window')
export default class NewButtons extends Component{
constructor(props){
super(props);
}
handlePress = () => {
this.props.onPress();
}
render(){
return(
<View style={styles.ButtonContainer}>
<Button light style={styles.mainButtons} onPress={this.handlePress()}>
<Text style={styles.textProps}>{this.props.text}</Text>
</Button>
</View>
);
}
}
const styles = StyleSheet.create({
textProps:{
fontFamily: 'PatuaOne',
color: '#ffffff',
},
mainButtons: {
backgroundColor: "#ff9900",
width: 250,
margin: 5,
color: '#ffffff',
justifyContent: 'center',
width: WIDTH -75,
borderRadius: 10,
},
ButtonContainer: {
alignItems: 'center',
}
})
I managed to remove this error by importing routes in App.js file and by calling it in index.js here is my code of App.js file.
import React, {Component} from "react";
import Routes from "./Routes";
const App = () => <Routes/>
export default App;

Trying to navigate to another screen based on text click, but got an error "undefined is not an object (evaluation navigate.navigateToScreen)"

I've been trying to navigate from Text to another screen but this error pops up, can anyone please help
This is a testing sheet for a bigger problem I have posted here Navigate when clicking on image doesn't work , I am trying to structure my code to navigate from an Image to a page. Thanks for helping
import React from 'react';
import { AppRegistry, StyleSheet, View, Image, TouchableOpacity, Text } from "react-native";
import { createAppContainer, createStackNavigator, StackActions, NavigationActions } from 'react-navigation'; // Version can be specified in package.json
import AddDocScreen from './Menu/AddDocScreen'
export default class Mock extends React.Component {
render() {
const navigate = this.props.navigation
return (
<View style={styles.container}>
<TouchableOpacity
onPress={() => navigate.navigateToScreen(navigationAction)}>
<View><Text>Click Me</Text></View>
</TouchableOpacity>
</View>
)
}
}
const navigationAction = NavigationActions.navigate({
routeName: 'AddDocSreen',
})
function navigateToScreen(navigationAction) {
() => {
return navigationAction
}
}
const doc = createStackNavigator({
AddDocScreen: { screen: AddDocScreen },
});
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'rgba(215,215,215,1)',
alignItems: 'center',
justifyContent: 'center',
},
})
Use it like this:
import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import AddDocScreen from './Menu/AddDocScreen'
class Mock extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center',backgroundColor: 'rgba(215,215,215,1)'}}>
<Text>Home Screen</Text>
<TouchableOpacity onPress={() => this.props.navigation.navigate('Details')}>
<View><Text>Click Me</Text></View>
</TouchableOpacity>
</View>
);
}
}
const RootStack = createStackNavigator(
{
Mock: Mock,
AddDocScreen: AddDocScreen,
{
initialRouteName: 'Mock',
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}

Navigation outside render function

I have a function to navigate to different component by checking in Async storage.
Here is my Loading Page Code:
import React from 'react';
import {
View,
Text
} from 'react-native';
import { AsyncStorage } from 'react-native';
export class LoadingScreen extends React.Component{
componentDidMount(){
async()=>{
try{
const usertoken = await AsyncStorage.getItem('token');
if(usertoken !== null ){
return this.props.navigation.navigate('Login');
}else{
return this.props.navigation.navigate('Register');
}
}catch(error){
this.props.navigation.navigate('Register')
}
};
}
render(){
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>This is loading...</Text>
</View>
);
}
}
But while running the app its not navigating to another Screen.
What am I doing wrong?
This is my register component:
import React , { Component } from 'react';
import {
View,
Text
} from 'react-native';
import { withNavigation } from 'react-navigation';
class RegisterScreen extends Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Register Screen</Text>
</View>
);
}
}
export default withNavigation(RegisterScreen);
Export both Login and Register using withNavigation. Like below.
import React, { Component } from 'react'
import { Text, View } from 'react-native'
import { withNavigation } from 'react-navigation';
class Login extends Component {
render() {
return (
<View>
<Text> Login </Text>
</View>
)
}
}
export default withNavigation(Login);

Fetching data from API in react native using redux

I am working on a react-native project where I am trying to fetch data from an api using axios library and display the data.So,my app first shows a splash screen and it then needs to navigate to a page which consists of tabs.The tabs will contain the data from the api.
So,I am trying to initialize my store in my Homepage which comes after the splash screen.I have my reducer and action defined separately in 2 different files.
App.js file
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { StackNavigator } from 'react-navigation';
import SplashScreen from './src/components/SplashScreen';
import HomeScreen from './src/components/HomeScreen';
const Navigation = StackNavigator({
Splash: {
screen: SplashScreen
},
Home: {
screen: HomeScreen
}
})
export default Navigation;
My SplashScreen component:
import React from 'react';
import { StyleSheet,
Text,
View,
} from 'react-native';
export default class SplashScreen extends React.Component {
static navigationOptions = {
header: null
}
componentWillMount() {
setTimeout(() => {
this.props.navigation.navigate('Home')
},2000)
}
render() {
return(
<View style={styles.container}>
<Text style={styles.welcome}>Splash Screen</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'skyblue'
},
welcome: {
color: '#FFF',
fontSize: 30
}
})
My HomeScreen component:
import React from 'react';
import { StyleSheet,
Text,
View,
} from 'react-native';
export default class SplashScreen extends React.Component {
static navigationOptions = {
header: null
}
componentWillMount() {
setTimeout(() => {
this.props.navigation.navigate('Home')
},2000)
}
render() {
return(
<View style={styles.container}>
<Text style={styles.welcome}>Splash Screen</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'skyblue'
},
welcome: {
color: '#FFF',
fontSize: 30
}
})
import React from 'react';
import { StyleSheet,
Text,
View,
} from 'react-native';
export default class SplashScreen extends React.Component {
static navigationOptions = {
header: null
}
componentWillMount() {
setTimeout(() => {
this.props.navigation.navigate('Home')
},2000)
}
render() {
return(
<View style={styles.container}>
<Text style={styles.welcome}>Splash Screen</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'skyblue'
},
welcome: {
color: '#FFF',
fontSize: 30
}
})
Action.js file
import axios from 'axios';
export const FETCH_DATA = 'fetch_data';
const API = 'https://api.myjson.com/bins/fz62x';
export function fetchData() {
const request = axios.get(API);
return dispatch => {
return request.then((data) => {
dispatch({
type: FETCH_DATA,
payload: data
})
})
}
}
My reducer
import { FETCH_DATA } from './actions';
export default function(state={}, action) {
switch(action.type) {
case FETCH_DATA:
return {
...state,
action.payload
};
default:
return state;
}
}
Can anyon please tell me if this the correct way? If not, then what is the correct way?
I would say there is no correct or incorrect way to do this. But I can share kind of a pattern that I usually use.
First I would create separate folders for different files. Actions in actions folder, reducers in reducers folder etc... I would create separate constants.js file and configureStore.js file and put them inside the project root directory.
I would drop Axios library and would just use Fetch API for data fetching. Considering your code I would do the following.
Create configureStore.js file inside your project root directory. I recommend you to use Redux-Thunk. You can find more info from here.
configureStore.js
import { createStore, applyMiddleware } from 'redux';
import app from './reducers';
import thunk from 'redux-thunk';
export default function configureStore() {
let store = createStore(app, applyMiddleware(thunk))
return store
}
App.js
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { StackNavigator } from 'react-navigation';
import configureStore from './configureStore';
import HomeScreen from './screens/HomeScreen';
const NavigationApp = StackNavigator({
HomeScreen: { screen: HomeScreen }
})
const store = configureStore()
export default class App extends Component {
render() {
return (
<Provider store={store}>
<NavigationApp />
</Provider>
);
}
}
Let's create constants.js and we place it inside the project root directory.
constants.js
export const FETCHING_TODOS = 'FETCHING_TODOS';
export const FETCH_TODOS_SUCCESS = 'FETCH_TODOS_SUCCESS';
export const FETCH_TODOS_FAILURE = 'FETCH_TODOS_FAILURE';
Now let's move on and create our action file which would be put inside the actions folder. Let's name it something like fetchToDos.js. Let's create a simple function using Fetch API.
fetchToDos.js
import { FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE, FETCHING_TODOS } from '../constants';
export function fetchToDos() {
return (dispatch) => {
dispatch(getTodos())
return(fetch('https://api.myjson.com/bins/fz62x'))
.then(res => res.json())
.then(json => {
return(dispatch(getToDosSuccess(json)))
})
.catch(err => dispatch(getToDosFailure(err)))
}
}
function getToDos() {
return {
type: FETCHING_TODOS
}
}
function getToDosSuccess(data) {
return {
type: FETCH_TODOS_SUCCESS,
data
}
}
function getToDosFailure() {
return {
type: FETCH_TODOS_FAILURE
}
}
fetchToDos.js with Axios
import { FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE, FETCHING_TODOS } from '../constants';
import axios from 'axios';
export function fetchToDos() {
return (dispatch) => {
dispatch(getUser())
axios.get('https://api.myjson.com/bins/fz62x')
.then(function (response) {
// handle your response here, create an object/array/array of objects etc...
// and return it in dispatch(getToDosSuccess(data over here))
return(dispatch(getToDosSuccess(response.data)))
})
.catch(err => dispatch(getToDosFailure(err)))
}
}
// rest is the same...
Moving on to reducers. Let's create two files - index.js, todos.js and put them inside reducers folder.
todos.js
import { FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE, FETCHING_TODOS } from '../constants';
const initialState = {
todos: [],
isFetching: false,
error: false
}
export default function todosReducer(state = initialState, action) {
switch(action.type) {
case FETCHING_TODOS:
return {
...state,
isFetching: true
}
case FETCH_TODOS_SUCCESS:
return {
...state,
isFetching: false,
todos: action.data
}
case FETCH_TODOS_FAILURE:
return {
...state,
isFetching: false,
error: true
}
default:
return state
}
}
index.js
import { combineReducers } from 'redux';
import todos from './todos';
const rootReducer = combineReducers({
todos
})
export default rootReducer
Basically "heavy lifting" is done. I would only create one screen because let's assume that users would tap back button (Android) while at home screen, they would end up on that splash screen. So in this example I am going to use one screen only.
HomeScreen.js
import React, { Component } from 'react';
import {
View,
Text,
ActivityIndicator
} from 'react-native';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { fetchTodos } from '../actions/fetchTodos';
class HomeScreen extends Component {
componentDidMount() {
this.props.fetchTodos()
}
render() {
const { todos, isFetching } = this.props.todos
if (isFetching) {
return(
<View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
<ActivityIndicator size={'large'} />
</View>
)
} else {
return(
<View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
<Text>todos.length</Text>
</View>
)
}
}
}
function mapStateToProps(state) {
return {
todos: state.todos
}
}
function mapDispatchToProps(dispatch) {
return {
...bindActionCreators({ fetchTodos }, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen)
I really hope that you find this concept useful because I can say from my experience that it helped me a lot when I first get started and it helped me to understand the whole concept of redux much better.
Sorry if there are any typos and errors. I was on a flow.