Navigation is not called right after user is unauthenticated - react-native

I am trying to logout the user and then send him to SignedOut screen but when I press on Sign Out it is calling the unauthUser function but then it restart the switch navigator to dashboard and I have to go in profile screen to tap again on Sign Out to go out. Any idea what am I doing wrong in all this?
Here is my button from Profile.js
<TouchableOpacity
onPress={() => onSignOut().then(() => {
this.props.dispatch(unauthUser)
navigation.navigate("SignedOut")
}
)}
>
<View style={styles.signOutButton}>
<Text style={styles.button}>SIGN OUT</Text>
</View>
</TouchableOpacity>
onSignOut() from Auth.js
export let USER_KEY = 'myKey';
export const onSignIn = async () => { await AsyncStorage.setItem(USER_KEY, 'true') };
export const onSignOut = async () => { await AsyncStorage.removeItem(USER_KEY) };
export const isSignedIn = () => {
return new Promise((resolve, reject) => {
AsyncStorage.getItem(USER_KEY)
.then(res => {
if (res !== null) {
// console.log('true')
resolve(true);
} else {
resolve(false);
// console.log('false')
}
})
.catch(err => reject(err));
});
};
unauthUser from authActions.js
exports.unauthUser = {
type: 'UNAUTH_USER'
}
and from authReducer.js
case 'UNAUTH_USER':
return {
user_id: undefined,
token: undefined
};
and here is my switch navigator
export const createRootNavigator = (signedIn = false) => {
return SwitchNavigator(
{
SignedIn: {
screen: SignedIn
},
SignedOut: {
screen: SignedOut
}
},
{
initialRouteName: signedIn ? "SignedIn" : "SignedOut"
}
);
};
class App extends Component {
constructor(props) {
super(props);
this.state = {
signedIn: false,
checkedSignIn: false
};
}
async componentWillMount() {
await isSignedIn()
.then(res => this.setState({ signedIn: res, checkedSignIn: true}))
.catch(err => alert("An error occurred"));
}
render() {
const { checkedSignIn, signedIn } = this.state;
// If we haven't checked AsyncStorage yet, don't render anything (better ways to do this)
if (!checkedSignIn) {
return null;
}
const Layout = createRootNavigator(signedIn);
return (
<SafeAreaView style={styles.safeArea}>
<View style={{flex: 1, backgroundColor: '#ffffff'}}>
<StatusBar barStyle="light-content"/>
<Layout />
<AlertContainer/>
</View>
</SafeAreaView>
)
}
};

Related

Cannot update a component (`ForwardRef(BaseNavigationContainer)`) while rendering a different component (`Signinscreen`)

I am getting the following warning:
Warning: Cannot update a component (ForwardRef(BaseNavigationContainer)) while rendering a different component (Signinscreen). To locate the bad setState() call inside Signinscreen, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
Signinscreen.js
import React, { Component, useEffect } from 'react'
import { View, Text, TextInput, Image } from 'react-native'
// STYLE
import styles from "./style"
// FORMIK
import { Formik } from 'formik'
// COMPONENT
import Navigationcomponent from "../../assets/components/navigationcomponent"
// STORAGE
import AsyncStorage from '#react-native-async-storage/async-storage'
// REDUX
import { connect } from 'react-redux'
// REDUX ACTION
import { initialaccount,user_signin } from '../../actions/index'
// YUP
import * as yup from 'yup'
// IMAGE
const mainimage = require("../../assets/images/mainlogo.png")
// SCREEN
import Homescreen from "../homescreen";
const SigninSchema = yup.object().shape({
username: yup
.string()
.min(6)
.max(12)
.required('Please, provide your username!')
.nullable(),
password: yup
.string()
.min(6)
.required('Please, provide your password!')
.nullable(),
})
const Signinscreen = ({navigation, initialaccount_d, user_signin_d, user_s}) => {
const storeData = async (values) => {
try {
// await AsyncStorage.setItem('me', JSON.stringify(values))
// await initialaccount_d(true)
// console.log(values)
await user_signin_d(values)
//
// navigation.navigate("Initialhomescreen")
} catch (e) {
// saving error
}
}
const validatecheck = () => {
AsyncStorage.setItem('me', JSON.stringify(user_s.usersignin_success))
navigation.navigate("Initialhomescreen")
// console.log(user_s.usersignin_success)
// if (user_s.usersignin_success != null) {
// // console.log(user_s.usersignin_success)
// // navigation.navigate("Initialhomescreen")
// if (user_s.usersignin_success.status == 200) {
// // console.log("user_s.usersignin_success")
// await AsyncStorage.setItem('me', JSON.stringify(user_s.usersignin_success))
// navigation.navigate("Initialhomescreen")
// }
// }
}
// ONBACK PRESS
useEffect(() => {
// validatecheck()
navigation.addListener('beforeRemove', e => {
// REMOVE INPUT VALUE BEFORE LEAVE SCREEN
user_signin_d(null)
});
},[])
if (user_s.usersignin_success != null && user_s.usersignin_success.status == 200) {
// validatecheck()
return(
<View>
{validatecheck()}
<Text>Load...</Text>
</View>
)
} else {
return(
<Formik
// validationSchema={SigninSchema}
initialValues={{ username: null, password: null}}
onSubmit={values => storeData(values)}>
{({ handleChange, handleSubmit, values, errors, touched }) =>
(
<View style={styles.main}>
<View style={styles.mainconf}>
<Image style={styles.imageconf} source={mainimage}></Image>
<View style={styles.inputconfmain}>
<Text style={styles.titleconf}>
Create now, for ever...
</Text>
<TextInput
style={styles.inputconf}
placeholder="username"
placeholderTextColor="gray"
onChangeText={handleChange('username')}
value={values.username}>
</TextInput>
{touched.username && errors.username &&
<Text style={{ fontSize: 12, color: 'red', alignSelf: "center" }}>{errors.username}</Text>
}
<TextInput
style={styles.inputconf}
placeholder="password"
placeholderTextColor="gray"
secureTextEntry={true}
onChangeText={handleChange('password')}
value={values.password}>
</TextInput>
{touched.password && errors.password &&
<Text style={{ fontSize: 12, color: 'red', alignSelf: "center" }}>{errors.password}</Text>
}
<Text onPress={handleSubmit} style={styles.btnsignupconf}>
Sign in
</Text>
{user_s.usersignin_success != null ? (user_s.usersignin_success.status == 400 ? <Text style={styles.warningmsg}>{user_s.usersignin_success.message}</Text> : (null)) : null}
</View>
</View>
</View>
)}
</Formik>
)
}
}
const mapStateToProps = (state) => ({
user_s: state.user
})
const mapDispatchToProps = (dispatch) => ({
initialaccount_d: (value) => dispatch(initialaccount(value)),
user_signin_d: (value) => dispatch(user_signin(value))
})
export default connect(mapStateToProps, mapDispatchToProps)(Signinscreen)
Homescreen.js
import React, { Component, useEffect, useState } from 'react'
import { View, Text, Image, SafeAreaView, BackHandler } from 'react-native'
// COMPONENT
import Navigationcomponent from "../../assets/components/navigationcomponent";
// STORAGE
import AsyncStorage from '#react-native-async-storage/async-storage';
// STYLE
import styles from "./style"
// REDUX
import { connect } from 'react-redux'
// REDUX ACTION
import { initialaccount } from '../../actions/index'
const Homescreen = ({navigation, initialaccount_s, initialaccount_d, user_s}) => {
// useEffect(() => {
// myaccount()
// }, []);
// myaccount = async () => {
// try {
// const value = await AsyncStorage.getItem('me')
// if(value !== null) {
// // value previously stored
// console.log('Yay!! you have account.')
// // await navigation.navigate("Homescreen")
// await initialaccount_d(true)
// } else {
// console.log('Upss you have no account.')
// // await navigation.navigate("Welcomescreen")
// await initialaccount_d(false)
// }
// } catch(e) {
// // error reading value
// }
// }
// Call back function when back button is pressed
const backActionHandler = () => {
BackHandler.exitApp()
return true;
}
useEffect(() => {
console.log(user_s.usersignin_success)
// Add event listener for hardware back button press on Android
BackHandler.addEventListener("hardwareBackPress", backActionHandler);
return () =>
// clear/remove event listener
BackHandler.removeEventListener("hardwareBackPress", backActionHandler);
},[])
// const validatecheck = () => {
// console.log(user_s.usersignin_success)
// // if (user_s.usersignin_success == null || user_s.usersignin_success.status == 400) {
// // navigation.navigate("Signinscreen")
// // }
// }
clearAll = async () => {
try {
await AsyncStorage.clear()
await initialaccount_d(false)
navigation.navigate("Initialscreen")
console.log('Done. cleared')
} catch(e) {
console.log('Upss you have no account.')
}
}
const getData = async () => {
try {
const value = await AsyncStorage.getItem('me')
if(value !== null) {
// value previously stored
console.log(value)
} else {
console.log('Upss you have no account.')
}
} catch(e) {
// error reading value
}
}
return(
<View style={styles.main}>
<View style={styles.logoutconf}>
<Text onPress={() => clearAll()}>LOGOUT</Text>
<Text onPress={() => getData()}>cek data</Text>
</View>
<Navigationcomponent style={styles.mainconf} />
</View>
)
}
const mapStateToProps = (state) => ({
initialaccount_s: state.user,
user_s: state.user
})
const mapDispatchToProps = (dispatch) => ({
initialaccount_d: (value) => dispatch(initialaccount(value))
})
export default connect(mapStateToProps, mapDispatchToProps)(Homescreen)
I encountered the same problem and I think that passing navigation.navigate("<screen_name>");} to another screen's onPress() prop (like
onPress={() => {navigation.navigate("<screen_name>");}
or
...
const navFunction = () => {
navigation.navigate("<screen_name>");
};
return(
<TouchableOpactiy onPress={() => {navFunction();} />
...
</TouchableOpacity>
);
...
).
I solved this by not passing the navigation from the onPress prop in the homeScreen and instead using the navigation prop inherent to the otherScreen.
// The homescreen.
const App = props => {
return(
<TouchableOpactiy
onPress={() => {
props.navigation.navigate('OtherScreen');
}}
>...</TouchableOpacity>
);
};
// The other screen.
const App = ({navigation}) => {
return(
<TouchableOpacity
onPress={() => {
navigation.navigate('HomeScreen');
}}
>...</TouchableOpacity>
);
};

React Native WebView App not exit on pressing back button

React Native WebView App not exit on pressing back button after setting Go back functionality on back button pressed. I want go back functionality on pressing back button when webview is not on home page and when webview is on home page then exit the app.
export default class WebView extends Component {
constructor (props) {
super(props);
this.WEBVIEW_REF = React.createRef();
}
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}
handleBackButton = ()=>{
this.WEBVIEW_REF.current.goBack();
return true;
}
onNavigationStateChange(navState) {
this.setState({
canGoBack: navState.canGoBack
});
}
render(){
return (
<WebView
source={{ uri: 'https://stackoverflow.com' }}
ref={this.WEBVIEW_REF}
onNavigationStateChange={this.onNavigationStateChange.bind(this)}
/>
);
}
}
Since you are managing the state of canGoBack inside onNavigationStateChange function, Change your handleBackButton function as below,
handleBackButton = () => {
if (this.state.canGoBack) {
this.WEBVIEW_REF.current.goBack();
return true;
}
}
Check below complete example
import React, { Component } from "react";
import { BackHandler } from "react-native";
import { WebView } from "react-native-webview";
export default class App extends Component {
WEBVIEW_REF = React.createRef();
state = {
canGoBack: false,
};
componentDidMount() {
BackHandler.addEventListener("hardwareBackPress", this.handleBackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", this.handleBackButton);
}
handleBackButton = () => {
if (this.state.canGoBack) {
this.WEBVIEW_REF.current.goBack();
return true;
}
};
onNavigationStateChange = (navState) => {
this.setState({
canGoBack: navState.canGoBack,
});
};
render() {
return (
<WebView
source={{ uri: "https://stackoverflow.com" }}
ref={this.WEBVIEW_REF}
onNavigationStateChange={this.onNavigationStateChange}
/>
);
}
}
Hope this helps you. Feel free for doubts.
I had this problem for quite a while but i have managed to resolve it. Problem that I experienced was that goBack (which is used as back event) function was triggered before onNavigationStateChange but somehow state was change although goBack function was called first.
const HomeScreen = () => {
const {web} = config;
const ref = useRef();
const [canGoBack, setCanGoBack] = useState(false);
const setupState = event => {
setCanGoBack(event?.canGoBack);
};
useEffect(() => {
const goBack = () => {
if (canGoBack === false) {
Alert.alert(
'Exit App',
'Do you want to exit app?',
[
{text: 'No', onPress: () => console.log('No'), style: 'cancel'},
{text: 'Yes', onPress: () => BackHandler?.exitApp()},
],
{cancelable: false},
);
}
ref?.current?.goBack();
return true;
};
BackHandler?.addEventListener('hardwareBackPress', () => goBack());
return () =>
BackHandler?.removeEventListener('hardwareBackPress', () => goBack());
}, [canGoBack]);
return (
<View style={styles.mainContainer}>
{/* last version 11.21.1 */}
<WebView
ref={ref}
source={{uri: web?.url}}
style={{flex: 1}}
cacheEnabled={web.cacheEnabled}
automaticallyAdjustContentInsets={false}
domStorageEnabled={true}
startInLoadingState={true}
allowsInlineMediaPlayback={true}
allowsBackForwardNavigationGestures
onNavigationStateChange={e => setupState(e)}
/>
</View>
);
};
export default HomeScreen;

Redux didn't update component

I'm pretty new in React-Native. I'm trying to display a list of devices, then go to one device, go to its informations, change the name, and with redux to change the name on all "screens" but it didn't work. I thing I a little bit lost between props, state and global state...
All the navigation, views and APIs works well.
This is my list view:
class DeviceList extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
};
this._getDevices();
// BINDING
this._goToDevice = this._goToDevice.bind(this);
this._goToDeviceAdd = this._goToDeviceAdd.bind(this);
}
componentDidUpdate() {
console.log("DEVICE_LIST componentDidUpdate : ");
console.log(this.props.devices);
}
_goToDevice(id = number) {
this.props.navigation.navigate('DeviceDetail', { idDevice: id })
}
_getDevices() {
restGet('devices')
.then(data => {
// REDUX
const action = { type: "INIT_DEVICE_LIST", value: data.datas };
this.props.dispatch(action);
// STATE
this.setState({
isLoading: false
});
});
}
_displayList() {
if (!this.state.loading && this.props.devices && this.props.devices.length > 0) {
return (
<View style=>
<FlatList
// data={this.state.devices}
data={this.props.devices}
keyExtractor={(item) => item.id.toString()}
renderItem={({item}) => <DeviceItem device={item} goToDevice={this._goToDevice}
/>}
/>
</View>
)
}
}
render() {
return (
<View style={styles.main_container}>
{/* LOADING */}
<Loading loading={this.state.isLoading}/>
{/* LIST */}
{this._displayList()}
</View>
);
}
}
// REDUX
const mapStateToProps = (state) => {
return {
devices: state.devices
};
};
export default connect(mapStateToProps)(DeviceList);
This is my Device Detail screen:
class DeviceDetail extends React.Component {
constructor(props) {
super(props);
this.state = {
device: null,
isLoading: true,
};
//
this._getDevice();
}
componentDidUpdate() {
console.log("DEVICE_DETAIL componentDidUpdate : ");
console.log(this.props.devices);
}
_goToDeviceInfo() {
this.props.navigation.navigate('DeviceInfo', { deviceId: this.state.device.id })
}
_getDevice() {
restGet('devices/' + this.props.navigation.getParam('idDevice'))
.then(data => {
// REDUX
const action = { type: "UPDATE_DEVICE", value: data.datas };
this.props.dispatch(action);
// STATE
this.setState({
device: this.props.devices.find(d => d.id === this.props.navigation.getParam('idDevice')),
isLoading: false,
});
});
}
_displayTile() {
if (this.state.device) {
return (
<View>
<Text>{this.state.device.name}</Text>
<TouchableOpacity onPress={() => this._goToDeviceInfo()}>
<FontAwesomeIcon icon={ faCog } size={ 18 } />
</TouchableOpacity>
</View>
)
}
}
render() {
return (
<View style={styles.main_container}>
{/* LOADING */}
<Loading loading={this.state.isLoading}/>
{/* TILE */}
{this._displayTile()}
</View>
);
}
}
// REDUX
const mapStateToProps = (state) => {
return {
devices: state.devices
};
};
export default connect(mapStateToProps)(DeviceDetail);
My Device Info Screen
class DeviceInfo extends React.Component {
constructor(props) {
super(props);
this.state = {
// device: this.props.navigation.getParam('device')
// device: this.props.devices.find(d => d.id === this.props.navigation.getParam('deviceId')),
};
// BINDING
this._saveItem = this._saveItem.bind(this);
}
componentDidUpdate() {
console.log("DEVICE_INFO componentDidUpdate : ");
console.log(this.props.devices);
}
_saveItem(name) {
// DB
// restPost('devices', {'id': this.state.device.id, 'name': name})
console.log();
restPost('devices', {'id': this.props.devices.find(d => d.id === this.props.navigation.getParam('deviceId')).id, 'name': name})
.then(data => {
// REDUX
const action = { type: "UPDATE_DEVICE", value: data.datas };
this.props.dispatch(action);
});
}
_removeDevice() {
Alert.alert(
'Supprimer l\'Appareil',
'Voulez-vous vraiment supprimer cet Appareil ?',
[
{
text: 'Annuler',
style: 'cancel',
onPress: () => console.log('Cancel Pressed'),
},
{
text: 'Oui, je souhaite le supprimer.',
onPress: () => {
// REDUX
const action = { type: "DELETE_DEVICE", value: this.state.device };
this.props.dispatch(action);
this.props.navigation.navigate('DeviceList')
}
},
],
{cancelable: false},
);
}
render() {
// const device = this.state.device;
const device = this.props.devices.find(d => d.id === this.props.navigation.getParam('deviceId'));
return (
<View style={ styles.main_container }>
<DeviceInfoItem device={device} title={'NOM'} value={device.name} edit={true} saveItem={this._saveItem}/>
<View style={styles.footer}>
<TouchableOpacity style={styles.startButton} onPress={() => this._removeDevice()}>
<FontAwesomeIcon icon={ faTrash } style={styles.footer_element_icon}/>
<Text style={styles.footer_element_text}>Supprimer l'Appareil</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
// REDUX
const mapStateToProps = (state) => {
return {
devices: state.devices
};
};
export default connect(mapStateToProps)(DeviceInfo);
My Device Info Item Component
class DeviceInfoItem extends React.Component {
constructor(props) {
super(props);
this.state = {
displayForm: false,
};
this.editText = '';
console.log(this.props);
}
componentDidUpdate() {
console.log("DEVICE_INFO_ITEM componentDidUpdate");
}
_displayValue() {
if (this.props.edit && this.state.displayForm) {
return (
<View>
<Input
placeholder={this.props.title}
// value={value}
leftIcon={<FontAwesomeIcon icon={ faTag } size={ 10 } />}
leftIconContainerStyle={ styles.inputIcon }
onChangeText={(text) => {
this.editText = text;
}}
/>
</View>
);
} else {
return (
<View>
<Text style={ styles.title }>{ this.props.title }</Text>
<Text style={ styles.value }>{ this.props.value }</Text>
</View>
);
}
}
_displayButton() {
if (this.props.edit) {
if (!this.state.displayForm) {
return (
<TouchableOpacity style={styles.edit} onPress={() => {
this.setState({
displayForm: true
})
}}>
<FontAwesomeIcon icon={ faPen } style={ styles.info_icon } size={ 14 } />
</TouchableOpacity>
);
} else {
return (
<TouchableOpacity style={styles.edit} onPress={() => {
this.props.saveItem(this.editText);
this.setState({
displayForm: false,
});
}}>
<FontAwesomeIcon icon={ faCheck } style={ styles.info_icon } size={ 14 } />
</TouchableOpacity>
);
}
}
}
render() {
return (
<View>
<View style={ styles.line }>
{ this._displayValue() }
{ this._displayButton() }
</View>
<Divider style={ styles.divider } />
</View>
);
}
}
export default DeviceInfoItem;
And my reducer:
const initialState = {
devices: []
};
function updateDevices(state = initialState, action) {
let nextState;
// CHECK IF DEVICE EXIST
const deviceIndex = state.devices.findIndex(device => device.id === action.value.id);
let device = state.devices.find(device => device.id === action.value.id);
switch (action.type) {
case 'INIT_DEVICE_LIST':
console.log('INIT_DEVICE_LIST');
nextState = {
...state,
devices: action.value
};
return nextState || state;
case 'ADD_DEVICE':
console.log('ADD_DEVICE');
nextState = {
...state,
devices: [...state.devices, action.value]
};
return nextState || state;
case 'DELETE_DEVICE':
console.log('DELETE_DEVICE');
if (deviceIndex !== -1) {
nextState = {
...state,
devices: state.devices.filter( (item, index) => index !== deviceIndex)
}
}
return nextState || state;
case 'UPDATE_DEVICE':
console.log('UPDATE_DEVICE');
if (deviceIndex !== -1) {
let d = state.devices;
d[deviceIndex] = action.value;
nextState = {
...state,
devices: d
}
}
return nextState || state;
default:
return state
}
}
export default updateDevices;
Delete Device works very well, the devices list in well updated. But the name updating didn't work. When I save, I got a console log ('DEVICE_INFO_ITEM componentDidUpdate) but not ('DEVICE_INFO componentDidUpdate). Why ?
create a file index.js in your reducer folder and do this:
import { combineReducers } from 'redux';
import myreducer from './Reducerfile';
export default combineReducers({
reducer: myreducer
});
And then
// REDUX
const mapStateToProps = (state) => {
return {
devices: state.reducer.devices
};
};
export default connect(mapStateToProps)(DeviceInfo);

How to set other first screen when I am logged in

How can I choose according value in AsyncStorage which screen should be displayed? I don't know why setting screen value 'Home' to InitialScreen variable doesn't work?
Once I log in login.js screen and I close app, after launching the app again I am navigated to login.js. But now I want to go to home.js screen.
Parent's file routes.js:
let InitialScreen
const RoutesNavigation = StackNavigator({
Login: { screen: Login },
Home: { screen: Home }
}, {
initialRouteName: InitialScreen,
navigationOptions: {
header: false,
}
});
export default class App extends Component {
constructor(props) {
super(props);
value = AsyncStorage.getItem('name');
if (value !== null) {
InitialScreen = 'Home'; //This doesn't change Initial screen!!!
console.log("JJJJJJJJJJJJJJJJJJ routes.js value !== null ");
}
}
render() {
return (
<RoutesNavigation />
);
}
}
This is login.js, where I store value from received json:
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
username: '',
password: '',
}
}
render() {
return (
<View style={styles.container}>
<TextInput
style={styles.textInput} placeholder='Username'
onChangeText={(username) => this.setState({ username })}
underlineColorAndroid='transparent'
/>
<TextInput
style={styles.textInput} placeholder='Password'
onChangeText={(password) => this.setState({ password })}
secureTextEntry={true}
underlineColorAndroid='transparent'
/>
<TouchableOpacity
style={styles.btn}
onPress={this.login}>
<Text>Log in</Text>
</TouchableOpacity>
</View>
);
}
login = () => {
var formData = new FormData();
formData.append('userName', this.state.username);
formData.append('password', this.state.password);
fetch('http://....', {
method: 'POST',
body: formData
})
.then((response) => response.json())
.then((responseJson) => {
console.log("JJJJJJJJJJJJJJJJJJJJJJJJJ name: " + responseJson.name);
AsyncStorage.setItem('name', responseJson.name);
this.props.navigation.navigate('Home');
})
.catch(() => {
console.log("JJJJJJJJJJJJJJJJJJ Wrong connection");
alert('Wrong connection');
})
}
}
This is home.js:
export default class Home extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.text}> Member area. You are logged in. </Text>
<TouchableOpacity
style={styles.btn}
onPress={this.logout}>
<Text>Log out</Text>
</TouchableOpacity>
</View>
);
}
logout = () => {
AsyncStorage.removeItem('name');
this.props.navigation.navigate('Login');
console.log("JJJJJJJJJJJJJJJJJJ Logged out");
}
}
Create your navigator in here:
value = AsyncStorage.getItem('name');
if (value !== null) {
InitialScreen = 'Home';
const RoutesNavigation = StackNavigator({
Login: { screen: Login },
Home: { screen: Home }
},{
initialRouteName: InitialScreen,
navigationOptions: {
header: false,
}
});
}
Because you are creating your navigator at the top with empty initial route but you are changing value in here so you must create here.
Hope it will work.
AsyncStorage is async.Because of the js nature thread won't wait result of this
AsyncStorage.getItem('name');
use callback with getItem
AsyncStorage.getItem('name',(error,result) => {
if (result!== null) {
//do something
}
});

React Native - mapStateToProps called but no re-rendering

I started React Native / Redux development for two weeks now, and i have some issues with the mapStateToProps and re-rendering.
Here are the facts :
mapStateToProps is called correctly with the right state (the new one)
render function is not called after the mapStateToProps
I have already check the troubleshooting page of Redux about that, and i dont have mutable issue
Here is the code :
Component
import React from 'react';
import { connect } from 'react-redux';
import { View, StyleSheet } from 'react-native';
import { Item, Input, Button, Text } from 'native-base';
import { signup } from './../actions/signup.action';
class Signup extends React.Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
confirmPassword: ''
};
}
render() {
console.log('rendering', this.props);
return (
<View style={styles.container}>
<Item rounded>
<Input placeholder='Email' onChangeText={(text) => this.setState({email: text})} value={this.state.email} />
</Item>
<Item rounded>
<Input placeholder='Mot de passe' secureTextEntry={true} onChangeText={(text) => this.setState({password: text})} value={this.state.password} />
</Item>
<Item rounded>
<Input placeholder='Confirmation du mot de passe' secureTextEntry={true} onChangeText={(text) => this.setState({confirmPassword: text})} value={this.state.confirmPassword} />
</Item>
<Button rounded onPress={(e) => this.onSignup(this.state.email, this.state.password)}>
<Text>Créer un compte</Text>
</Button>
<Text>{this.props.isSignupLoading}</Text>
<Text>{this.props.signupError}</Text>
</View>
)
}
onSignup = (email, password) => {
this.props.signup(email, password);
}
}
const mapStateToProps = (state) => {
return {
isSignupLoading: state.isSignupLoading,
isSignupSuccess: state.isSignupSuccess,
signupError: state.signupError
};
};
const mapDispatchToProps = (dispatch) => {
return {
signup: (email, password) => dispatch(signup(email, password))
};
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#F5FCFF",
},
});
export default connect(mapStateToProps, mapDispatchToProps)(Signup);
Actions
import { firebaseAuth } from './../config/firebase';
export const signupLoading = (isSignupLoading) => {
return {
type: 'SIGNUP_LOADING',
isSignupLoading
};
}
export const signupSuccess = (isSignupSuccess) => {
return {
type: 'SIGNUP_SUCCESS',
isSignupSuccess
};
};
export const signupError = (error) => {
return {
type: 'SIGNUP_ERROR',
signupError: error.message
};
};
export const signup = (email, password) => {
return (dispatch) => {
dispatch(signupLoading(true));
firebaseAuth.createUserWithEmailAndPassword(email, password)
.then(() => dispatch(signupLoading(false)))
.then(() => {
console.log("signup.action#signup success");
dispatch(signupSuccess(true));
})
.catch((error) => {
console.log("signup.action#signup failed - " + error);
dispatch(signupLoading(false));
dispatch(signupError(error));
});
};
};
Reducer
const defaultState = {
isSignupLoading: false,
isSignupSuccess: false,
signupError: null
};
const signupReducer = (state = defaultState, action) => {
switch (action.type) {
case 'SIGNUP_LOADING':
return Object.assign({}, state, {
isSignupLoading: action.isSignupLoading
});
case 'SIGNUP_SUCCESS':
return Object.assign({}, state, {
isSignupSuccess: action.isSignupSuccess
});
case 'SIGNUP_ERROR':
return Object.assign({}, state, {
signupError: action.signupError
});
default:
return state;
}
}
export default signupReducer;
If you want more code about what i have done, ask me.
Thanks for your help.
Best regards.
I met the same issue as you. You should fix it by modifying your mapStateToProps as following. This is due to signupReducer/signupReducer/signupError is under signupReducer not state.
const mapStateToProps = (state) => {
return {
isSignupLoading: state.signupReducer.isSignupLoading,
isSignupSuccess: state.signupReducer.isSignupSuccess,
signupError: state.signupReducer.signupError
};
};