I am building a React Native app, mainly for verifying tickets, to be used by event administrators. The back-end is served by a Laravel app with a working OAuth2-server. I have a working login against that server but now I need to store the access token, to request data, such as events, and to verify if a ticket is matched for a given event.
I'm trying to implement Redux to store the access token etc. The login form I have updates the store via actions correctly, but I can't get it to work with the access token.
Here is the login screen:
import React, { Component } from 'react';
import { Text, View, TextInput, Button } from 'react-native';
import { connect } from 'react-redux'
import StringifyBody from './../lib/oauth2/StringifyBody'
import { login, storeTokens } from '../redux/actions/auth.js'
class Login extends Component {
constructor (props) {
super(props);
this.state = {
route: 'Login',
loading: false,
email: '',
password: '',
accessToken: '',
};
}
handleClick (e) {
e.preventDefault();
return new Promise(function(resolve, reject) {
var data = StringifyBody(this.state.password, this.state.email)
// XHR settings
var xhr = new XMLHttpRequest()
xhr.withCredentials = true
xhr.onerror = function() {
reject(Error('There was a network error.'))
}
xhr.open("POST", "http://192.168.0.141/oauth/access_token")
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded")
xhr.send(data)
xhr.onloadend = function() {
if (xhr.status === 200) {
var parsedJson = JSON.parse(xhr.response)
responseArray = []
for(var i in parsedJson) {
responseArray.push([parsedJson [i]])
}
// assign values to appropriate variables
let accessToken = responseArray[0];
console.log('access token is: ' + accessToken)
accessToken => this.setState({ access_token: accessToken })
this.props.tokenStore(this.state.accessToken) // This doesn't work: "cannot read property 'tokenStore' of undefined"
resolve(xhr.response)
} else {
reject(Error('Whoops! something went wrong. Error: ' + xhr.statusText))
}
}
})
.done(() => {
this.props.onLogin(this.state.email, this.state.password); // This works
})
}
render() {
return (
<View style={{padding: 20}}>
<Text style={{fontSize: 27}}>{this.state.route}</Text>
<TextInput
placeholder='Email'
autoCapitalize='none'
autoCorrect={false}
keyboardType='email-address'
value={this.state.email}
onChangeText={(value) => this.setState({ email: value })} />
<TextInput
placeholder='Password'
autoCapitalize='none'
autoCorrect={false}
secureTextEntry={true}
value={this.state.password}
onChangeText={(value) => this.setState({ password: value })} />
<View style={{margin: 7}}/>
<Button onPress={(e) => this.handleClick(e)} title={this.state.route}/>
</View>
);
}
}
const mapStateToProps = state => {
return {
isLoggedIn: state.auth.isLoggedIn,
access_token: state.auth.access_token,
}
}
const mapDispatchToProps = (dispatch) => {
return {
onLogin: (email, password) => { dispatch(login(email, password)); },
tokenStore: (accessToken) => { dispatch(storeTokens(accessToken)) },
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Login);
Redux actions:
export const login = (email, password) => {
return {
type: 'LOGIN',
email: email,
password: password
};
};
export const logout = () => {
return {
type: 'LOGOUT'
};
};
export const storeTokens = () => {
return {
type: 'STORE_TOKENS',
access_token: accessToken,
}
}
And finally the reducers:
const defaultState = {
isLoggedIn: false,
email: '',
password: '',
access_token: '',
};
export default function reducer(state = defaultState, action) {
switch (action.type) {
case 'LOGIN':
return Object.assign({}, state, {
isLoggedIn: true,
email: action.email,
password: action.password
});
case 'LOGOUT':
return Object.assign({}, state, {
isLoggedIn: false,
email: '',
password: ''
});
case 'STORE_TOKENS':
return Object.assign({}, state, {
access_token: action.accessToken,
})
default:
return state;
}
}
I've also tried passing the data to this.props.storeTokens (the actual action) in a componentDidMount() which gives me the error undefined is not a function (evaluating 'this.props.storeTokens()') componentDidMount Login.js:57:8
My question then is: How do I store the variable I get from my XHR POST in the redux store? Why is this.props.tokenStore and this.props.storeToken not defined?
Hey thats a mistake owing to javascript concept. You are calling
this.props.tokenStore(this..state.accessToken) // This doesn't work: "cannot read property 'tokenStore' of undefined"
inside a function defined using ES5 syntax. either you store the reference of this outside the function in some variable and then use that variable instead of this. The other option is define arrow function instead. So change your function keyword into
() =>
and this should work. this as of now in your implementation doesn't point to component that you are thinking
Related
I have my login working, it logs me in without problems and it enters the screen that I want, but when I want to show the information on the screen of the user that logs in, I have not been able to show the user information on the screen that it should load from database. I have tried to create an interface where I add the names of the fields as they are in the database but when calling them from my screen nothing is loaded
what I need is that when I log in to my screen protectedScreen.ts it shows me the data of the user that logs in
mi db: Tabla : usuarios campos: id, name, email, password, tipo_usuario
AuthContext.ts //where valid and login
import React,{ createContext, useEffect, useReducer } from "react";
import AsyncStorage from '#react-native-async-storage/async-storage';
import { SafeAreaView, StyleSheet, TextInput, View, Alert, TouchableOpacity, Text } from "react-native";
import cafeApi from "../api/cafeApi";
import { LoginData, LoginResponse, RegisterData, Usuarios } from "../interfaces/appinterfaces";
import { authReducer, AuthState } from "./AuthReducer";
type AuthContextProps = {
errorMessage: string;
token: string | null;
user: Usuarios | null;
status: 'checking' | 'authenticated' | 'not-authenticated';
signUp: (RegisterData: RegisterData) => void;
signIn: (loginData : LoginData) => void;
logOut: () => void;
removeError: () => void;
}
const authInicialState: AuthState = {
status:'checking',
token: null,
user: null,
errorMessage:''
}
export const AuthContext = createContext({} as AuthContextProps);
export const AuthProvider = ({children}: any) =>{
const[state, dispatch] = useReducer(authReducer,authInicialState);
useEffect(() =>{
checkToken();
}, [])
const checkToken = async () =>{
const token = await AsyncStorage.getItem('token');
//No token, no autenticado
if (!token) return dispatch({ type:'notAuthenticated'});
//hay token
const resp = await cafeApi.get('/usuarios/middlewares/Auth.php');
if(resp.status !== 200){
return dispatch({type:'notAuthenticated'});
}
await AsyncStorage.setItem('token', resp.data.token)
dispatch({
type: 'signUp',
payload:{
token: resp.data.token,
user: resp.data.usuarios
}
})
}
const signIn = async({correo, password}: LoginData) => {
try {
await fetch('https://www.miweb.com/apiPlooy/usuarios/login.php',
{
method:'POST',
headers:{
'Accept': 'application/json',
'content-Type': 'application/json'
},
body: JSON.stringify({"email":correo, "password" : password})
}).then(res => res.json())
.then(resData => {
if(resData.message == "Ha iniciado sesión correctamente.") {
dispatch({
type: 'signUp',
payload: {
token: resData.token,
user: resData.usuarios
}
});
}else{
Alert.alert(resData.message)
}
});
}catch (error) {
dispatch({type: 'addError',
payload: error.response.data.msg || 'Información incorrecta'})
}
};
return(
<AuthContext.Provider value={{
...state,
signUp,
signIn,
logOut,
removeError,
}}>
{children}
</AuthContext.Provider>
)
}
appinterfaces.ts // where I add the user db fields to be able to show them on the screen when I login
export interface LoginData{
correo: string;
password: string;
}
export interface LoginResponse{
usuarios: Usuarios;
token: string;
}
export interface Usuarios{
tipo_usuario: String;
email: String;
password: String;
name: String
}
ProtectedScreen.ts // This is my screen when I log in and where I want to show some field of my user that I log in but it is not shown.
interface Props extends StackScreenProps<any, any>{}
export const ProtectedScreen = ({navigation}: Props) => {
const {user, token} = useContext(AuthContext);
const {email, password, name, onChange} = useForm({
email:'',
password:'',
name:'',
});
return (
<>
<View style={loginStyles.formContainer}>
<Text>BIENVENIDO
Tipo usuario: {JSON.stringify(user.tipo_usuario, null, 50)}
</Text>
</View>
</>
)
}
code and api: https://github.com/Giovannychvz/react-native
//I add what I have found in case it is of any use I have a project in reactjs and it uses the same api as the react native project and when I log in it loads the data of the user who logged in, I don't know if it is of any use but I send the context of react:
Note: the only strange thing I found in this context of react is that user-info.php is being called and I am not calling this file from react native because the problem must be there but I have not been able to solve it.
context.js
import React, { createContext,Component } from "react";
import axios from 'axios'
import history from '../components/history';
export const MyContext = createContext();
// Define the base URL
const Axios = axios.create({
baseURL: 'https://www.miweb.com/apiPlooy/usuarios/',
});
class MyContextProvider extends Component{
constructor(){
super();
this.isLoggedIn();
history.push('/');
}
// Root State
state = {
showLogin:true,
isAuth:false,
theUser:null,
}
// Toggle between Login & Signup page
toggleNav = () => {
const showLogin = !this.state.showLogin;
this.setState({
...this.state,
showLogin
})
}
// On Click the Log out button
logoutUser = () => {
localStorage.removeItem('loginToken');
localStorage.clear();
history.push('/');
this.setState({
...this.state,
isAuth:false
})
}
registerUser = async (user) => {
// Sending the user registration request
const register = await Axios.post('register.php',{
name:user.name,
email:user.email,
password:user.password
});
return register.data;
}
loginUser = async (user) => {
// Sending the user Login request
const login = await Axios.post('login.php',{
email:user.email,
password:user.password
});
return login.data;
}
// Checking user logged in or not
isLoggedIn = async () => {
const loginToken = localStorage.getItem('loginToken');
// If inside the local-storage has the JWT token
if(loginToken){
//Adding JWT token to axios default header
Axios.defaults.headers.common['Authorization'] = 'bearer '+loginToken;
// Fetching the user information
const {data} = await Axios.get('user-info.php');
// If user information is successfully received
if(data.success && data.user){
this.setState({
...this.state,
isAuth:true,
theUser:data.user
});
}
}
}
render(){
const contextValue = {
rootState:this.state,
toggleNav:this.toggleNav,
isLoggedIn:this.isLoggedIn,
registerUser:this.registerUser,
loginUser:this.loginUser,
logoutUser:this.logoutUser
}
return(
<MyContext.Provider value={contextValue}>
{this.props.children}
</MyContext.Provider>
)
}
}
export default MyContextProvider;
I am using React-typescript for my. I have one login page where there are two input fields. one is email and password. i have created one state and inside the state there email password and loading. Default input fields works fine, I have target my input fields with id. I have decided, I will create global input fields and custom props. When I used global input fields then it does not target the id and throws me this error: React-typescript: TypeError: Cannot read property 'id' of undefined. I am pretty sure in my typescript onChange throws me that error. But Don't know to how to fix it. Here is my code in Codesandbox.
This is my Login form
import React, { ReactElement, useState } from "react";
import { TextInput } from "./input";
interface Props extends PageProps {}
export default function SignIn({}: Props): ReactElement {
const [state, setState] = useState({
email: ``,
password: ``,
loading: false
});
const { loading, email, password } = state;
const handleSignIn = (e: React.ChangeEvent<HTMLInputElement>) => {
setState({
...state,
[e.target.id]: e.target.value //This is id which throws me error
});
};
const onSubmit = async (e) => {
e.preventDefault();
console.log(state);
setState({
loading: true,
...state
});
const response = await fetch(
"https://run.mocky.io/v3/beec46b8-8536-4cb1-9304-48e96d341461",
{
method: `POST`,
headers: {
Accept: `application/json`,
"Content-Type": `application/json`
},
body: { state }
}
);
console.log(response);
if (response.ok) {
setState({ ...state, loading: false });
alert(`login succs`);
} else {
alert(`login failed`);
}
};
return (
<div>
<TextInput
type="text"
value={email}
onChange={handleSignIn}
id="email"
required
/>
<TextInput
type="password"
value={password}
onChange={handleSignIn}
id="password"
required
/>
<button type="submit" name="action" onClick={onSubmit} disabled={loading}>
{" "}
{loading ? `loading...` : `save`}
</button>
</div>
);
}
this is my global input
import React, { ReactElement } from "react";
import styled from "styled-components";
interface Props {
value: string;
onChange: (e: string) => void;
error?: string;
id?: string;
}
const Input = styled.input``;
// eslint-disable-next-line func-style
export function TextInput({ value, onChange, error, id }: Props): ReactElement {
return (
<div>
<Input
value={value}
onChange={(e) => onChange(e.target.value)}
error={error}
id={id}
/>
</div>
);
}
I found my solution: I have created two handle changes functions, one for email and one for password..
`const handleEmail = (email: string) => {
setState({
...state,
email
});
};
const handlePassword = (password: string) => {
setState({
...state,
password
});
};`
I have implemented redux with my login form which is not working properly
it shows ERROR 'Cannot read property 'isAuthenticated' of undefined. which i think it means that redux is not implemented properly.
Please Help!
if you need any other file,tell me i will share it to you.
LoginForm.js
import React, {Component} from 'react';
import {
//StyleSheet,
View,
Text,
TextInput,
Button
} from 'react-native';
import {reduxForm,Field} from 'redux-form';
import {connect} from 'react-redux';
import {login} from './authActions';
const validate = values =>{
const errors = {};
if(!values.email){
errors.email="Please fill the email"
return errors;
}
if(!values.password){
errors.password="Please fill the password"
return errors;
}
}
const myFields = ({label,meta:{error,touched}, input:{onChange}}) =>{
return(
<View>
<Text>{label}</Text>
<TextInput style={{borderWidth:1,width:300,marginBottom:10}}
onChangeText={onChange}/>
{touched && (error && (<Text style={{color:'red'}}>{error}</Text>))}
</View>
);
}
const passFields = ({label,meta:{error,touched}, input:{onChange}}) =>{
return(
<View>
<Text>{label}</Text>
<TextInput style={{borderWidth:1,width:300,marginBottom:10}}
secureTextEntry={true}
onChangeText={onChange}/>
{touched && (error && (<Text style={{color:'red'}}>{error}</Text>))}
</View>
);
}
const submitbtn = values =>{
//alert(`here are the values ${JSON.stringify(values)}`);
//console.log(input.value);
this.props.login(values);
}
const myLoginForm = props => {
const {handleSubmit} = props;
return(
<View>
<Field
name="email"
component={myFields}
label="Email"/>
<Field
name="password"
component={passFields}
label="Password"
/>
<Button title="Submit"
onPress={handleSubmit(submitbtn)}/>
</View>
);
}
const LoginForm = reduxForm({
form:'loginform',
validate
})(myLoginForm);
const mapStateToProps =(state) =>({
isAuthenticated: state.auth.isAuthenticated
});
export default connect(mapStateToProps,{login})(LoginForm);
authActions.js
import axios from 'axios';
//import { returnErrors } from './errorActions';
export const register = ({username, name, email, password}) => {
return (dispatch, getState) => {
const config = {
headers : {
'Content-type' : 'Application/json'
}
}
const body = JSON.stringify({
username,
name,
email,
password
})
axios.post('http://localhost:5000/users/register', body , config )
.then(res => dispatch({
type : 'REGISTER_SUCCESS',
payload : res.data
}))
.catch(err => {
dispatch(returnErrors(err.response.data, err.response.status, 'REGISTER_FAIL'));
dispatch({
type : 'REGISTER_FAIL'
})
});
};
};
export const login = ({username, password}) => {
return (dispatch, getState) => {
const config = {
headers : {
'Content-type' : 'Application/json'
}
}
const body = JSON.stringify({
username,
password
})
axios.post('http://localhost:5000/users/login', body , config )
.then(res => dispatch({
type : 'LOGIN_SUCCESS',
payload : res.data
}))
.catch(err => {
dispatch(returnErrors(err.response.data, err.response.status, 'LOGIN_FAIL'));
dispatch({
type : 'LOGIN_FAIL'
})
});
};
}
export const logout = () => {
return {
type : 'LOGOUT_SUCCESS'
}
}
export const loadUser = () => {
return (dispatch, getState) => {
dispatch({
type: 'USER_LOADING',
});
axios.get('http://localhost:5000/users/auth' , tokenConfig(getState))
.then(res => dispatch({
type: 'USER_LOADED',
payload : res.data
}))
.catch(err => {
dispatch(returnErrors(err.response.data.message, err.response.status));
dispatch({
type : 'AUTH_ERROR'
});
})
}
}
//
export const tokenConfig = (getState) => {
const token = getState().auth.token;
const config = {
headers : {
'content-type' : 'Application/json',
}
}
if(token) {
config.headers['auth'] = token;
}
return config;
}
authReducer.js
const initState = {
toke: localStorage.getItem('token'),
isAuthenticated: null,
isLoading: null,
user: null
};
const authReducer = (state = initState, action) => {
switch(action.type){
case 'USER_LOADING':
return{
...state,
isLoading: true
}
case 'USER_LOADED':
return{
...state,
isLoading: false,
isAuthenticated:true,
user:action.payload
}
case 'REGISTER_SUCCESS':
case 'LOGIN_SUCCESS':
localStorage.setItem('token', action.payload.token)
return{
...state,
...action.payload,
isLoading: false,
isAuthenticated:true,
}
case 'AUTH_ERROR':
case 'LOGOUT_SUCCESS':
case 'LOGIN_FAIL':
case 'REGISTER_FAIL':
localStorage.removeItem('token')
return{
token: null,
user: null,
isLoading: false,
isAuthenticated:false,
}
default:
return state;
}
}
export default authReducer
Please check file where you combine your reducers, there's possibility that you put your reducer as something other than "auth" or even you forgotten to put the reducer here.
You can install "redux-devtools-extension" package and it's chrome extension to see which reducers are connected to your redux state and debug it more easily. Also, redux-form requires you to pass the form reducer you create along with all the other reducers you have in 'combineReducers'. Follow the instructions on their docs https://redux-form.com/8.2.2/docs/gettingstarted.md/
hope this helps :)
I am having troubles with getting the state in my HomeComponent.js . Every time I try to print it, it return "undefined" .
I've tried different ways to call onPress in my Home component (e.g. onPress={this.printState()}, but none work)
This is my HomeComponent.js
//import statements
const mapStateToProps = state => {
return {
jobTitles: state.jobTitles
}
}
const mapDispatchToProps = dispatch => ({
fetchJobTitles: () => dispatch(fetchJobTitles())
});
class Home extends Component {
constructor(props) {
super(props);
this.state = {
jobInputValue: '',
addressInputValue: ''
};
}
componentDidMount() {
this.props.fetchJobTitles();
}
printState = () => {
console.log('State is: ' +
JSON.stringify(this.state.jobTitles));
}
render() {
return (
<ImageBackground style={styles.bkgImage} source={require('../assets/homepage_background.jpg')}>
//JSX goes here
<Button
title="CAUTĂ"
type="outline"
underlayColor={colors.red}
titleStyle={styles.buttonTitleStyle}
color={colors.red}
style={styles.buttonStyle}
onPress={this.printState}
/>
</ImageBackground>
);
}
}
//some styles
export default connect(mapStateToProps, mapDispatchToProps)(Home);
This is my reducer (jobTitles.js):
import * as ActionTypes from '../ActionTypes';
export const jobTitles = (state = { errMess: null,
jobTitles:[]}, action) => {
switch (action.type) {
case ActionTypes.GET_JOB_TITLES:
return {...state, errMess: null, jobTitles: action.payload};
case ActionTypes.JOB_TITLES_FAILED:
return {...state, errMess: action.payload};
default:
return state;
}
};
And this is my Action Creator:
import * as ActionTypes from './ActionTypes';
import { baseUrl } from '../shared/baseUrl';
export const fetchJobTitles = () => (dispatch) => {
return fetch(baseUrl + 'api/jobs/job_keywords')
.then(response => {
if (response.ok) {
return response;
} else {
var error = new Error('Error ' + response.status + ': ' +
response.statusText);
error.response = response;
throw error;
}
},
error => {
var errmess = new Error(error.message);
throw errmess;
})
.then(response => response.json())
.then(jobTitles => dispatch(addJobTitles(jobTitles)))
.catch(error => dispatch(jobTitlesFailed(error.message)));
};
export const jobTitlesFailed = (errmess) => ({
type: ActionTypes.JOB_TITLES_FAILED,
payload: errmess
});
export const addJobTitles = (jobTitles) => ({
type: ActionTypes.GET_JOB_TITLES,
payload: jobTitles
});
This is how the response from the API looks like:
"jobTitles": Object {
"results": Array [
"Engineer",
"Software",
"Software Architect",
"Software Consultant",
"Solution Architect",
"System Architect"
]
}
I expected the console.log() statement from the print() function in the HomeComponent.js to print the JSON response from the API, but instead it returns "undefined". Any ideas why?
Any help will be greatly appreaciated!
In your code :
this.state = {
jobInputValue: '',
addressInputValue: ''
};
What you try to print :
this.state.jobTitles
Of course it's undefined ! Either log this.props.jobTitles or set state jobTitles to print what you want.
You should use this.props.jobTitles
The mapStateToProps puts data from the redux state into the props of the component. this.state only holds the local state of the component. So jobInputValue and addressInputValue in this case. Everything from mapStateToProps and mapDispatchToProps will end up in the props. (As the name of the function indicates)
I have react native application with redux, where user get nevigated to home component after successful login. But home component get rendered before it receive user profile through store. If I use 'Home' component as connected component then on re-render it receives profile.
It is a correct flow or do I able to delay rendering of 'Home' till store is populated with new data.
Here is code
Types
export const FETCH_PROFILE = 'FETCH_PROFILE';
export const UPDATE_PROFILE = 'UPDATE_PROFILE';
export const DELETE_PROFILE = 'DELETE_PROFILE';
export const FETCH_STREAMS = 'FETCH_STREAMS';
Reducer
export default function profile(state = {}, action) {
switch (action.type) {
case types.FETCH_PROFILE:
return {
...state,
profile: action.profile
}
case types.UPDATE_PROFILE:
return {
...state,
profile: action.profile
}
case types.DELETE_PROFILE:
return {
...state,
profile: null
};
default:
return state;
}
}
Actions
var PROFILE_KEY = "#myApp:profile";
export function fetchProfile() {
return dispatch => {
AsyncStorage.getItem(PROFILE_KEY)
.then((profileString) => {
dispatch({
type: types.FETCH_PROFILE,
profile: profileString ? JSON.parse(profileString) : {}
})
})
}
}
export function updateProfile(data) {
return dispatch => {
AsyncStorage.setItem(PROFILE_KEY, JSON.stringify(data))
.then(() => {
dispatch({
type: types.UPDATE_PROFILE,
profile: data
})
})
}
}
export function deleteProfile() {
return dispatch => {
AsyncStorage.removeItem(PROFILE_KEY)
.then(() => {
dispatch({
type: types.DELETE_PROFILE
})
})
}
}
Login Component
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: "",
error: "",
showProgress: false,
};
}
_focusNextField(nextField) {
this.refs[nextField].focus();
}
_onLoginPressed() {
this.setState({showProgress: true});
this._login();
}
async _login() {
try {
let response = await fetch( BASE_URL + url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
user: {
email: this.state.username,
password: this.state.password,
}
})
});
let res = await response.text();
if (response.status >= 200 && response.status < 300) {
let user = JSON.parse(res);
this.props.updateProfile(user.user);
this.setState({showProgress: false});
this.props.navigator.replace({name: 'Home'});
}
else {
let error = JSON.parse(res);
throw error.errors;
}
} catch(error) {
this.setState({error: error});
this.setState({showProgress: false});
console.log("error " + error);
}
}
render() {
return (
<View style={styles.loginBox}>
<TextInput
ref="username"
value={this.state.username}
placeholder="Username"
keyboardType="email-address"
onChangeText={(username) => this.setState({username}) }
onSubmitEditing={() => this._focusNextField('password')}/>
<TextInput
ref="password"
placeholder="Password"
value={this.state.password}
secureTextEntry={true}
onChangeText={(password) => this.setState({password}) }
returnKeyType="go"/>
<Button textStyle={{fontSize: 14}} onPress={this._onLoginPressed.bind(this)} style={{marginTop: 30}}>
Sign In
</Button>
</View>
);
}
}
const styles = StyleSheet.create({
loginBox: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
alignItems: 'stretch',
margin: 10,
}
});
var {updateProfile} = require('../Actions');
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
module.exports = connect(
null,
(dispatch) => {
return bindActionCreators({updateProfile}, dispatch)
}
)(Login)
Home
class Home extends React.Component {
render() {
return (
<View style={{flex: 1, backgroundColor: '#fff'}}>
<Text style={{margin: 10, fontSize: 15, textAlign: 'left'}}>I'm in the Drawer!</Text>
<Text>Auth key : {this.props.profile ? this.props.profile.authentication_token : 'authentication_token'}</Text>
</View>
);
}
}
//module.exports = Home;
import { connect } from 'react-redux';
module.exports = connect(
(state) => {
return {
profile: state.profile
}
},
null
)(Home)
If you're using redux-thunk, you can delay the transition until data is loaded. You need to change some small things.
Add return to action creator.
export function updateProfile(data) {
return dispatch => {
return AsyncStorage.setItem(PROFILE_KEY, JSON.stringify(data))
.then(() => {
dispatch({
type: types.UPDATE_PROFILE,
profile: data
})
})
}
}
add await
if (response.status >= 200 && response.status < 300) {
let user = JSON.parse(res);
await this.props.updateProfile(user.user);
this.setState({showProgress: false});
this.props.navigator.replace({name: 'Home'});
}