React native redux fbsdk login - react-native

I want to create a facebook login on my app, using react-native, redux and react-native-fbsdk. Actually, I'm face to a a problem, when I am on the first state (not logged in) I see this state :
and when I click on the login button I have this state :
The authenticating is set to true, but the application stay on authenticating, and even if I wait like 5 minutes, nothing happened after .. I think that it missing something in my code but I don't know what.
I past my code here.
The reducer :
import {
AUTH_SUCCESS,
AUTH_FAILURE,
AUTH_STARTED,
AUTH_ERROR,
AUTH_FAILURE_REMOVE,
LOGOUT
} from '../actions/types';
const initialState = {
authenticating: false,
authToken: null,
authError: null,
facebookToken: null,
facebookProfile: null
}
function authReducer(state = initialState, action) {
switch(action.type) {
case AUTH_STARTED:
return Object.assign({}, state, {
authenticating: true,
loginText: 'Connexion..'
});
case AUTH_SUCCESS:
return Object.assign({}, state, {
authenticating: false,
authToken: action.authToken,
facebookToken: action.facebookToken,
facebookProfile: action.facebookProfile,
});
case AUTH_FAILURE:
return Object.assign({}, state, {
authenticating: false,
authError: action.authError.message,
});
case AUTH_FAILURE_REMOVE:
return Object.assign({}, state, {
authError: null,
});
case LOGOUT:
return Object.assign({}, state, {
authenticating: false,
authToken: null,
facebookToken: null,
facebookProfile: null,
loginText: null,
});
default:
return state;
}
}
export default authReducer;
The action : (all actions are in separate file called types.js)
import { facebookLoginAPI, getFacebookInfoAPI } from '../src/facebook';
import { getServerAuthToken } from '../src/auth';
import {
AUTH_STARTED,
AUTH_SUCCESS,
AUTH_FAILURE,
AUTH_ERROR,
AUTH_FAILURE_REMOVE,
LOGOUT
} from './types';
export function authStarted() {
return {
type: AUTH_STARTED,
};
}
export function authSuccess(facebookToken, facebookProfile, serverAuthToken){
return {
type: AUTH_SUCCESS,
facebookToken,
facebookProfile,
authToken: serverAuthToken,
};
}
export function authFailure(authError){
return {
type: AUTH_FAILURE,
authError,
};
}
export function authFailureRemove() {
return {
type: AUTH_FAILURE_REMOVE,
};
}
export function logout() {
return {
type: LOGOUT,
};
}
export function facebookLogin() {
return (dispatch) => {
dispatch(authStarted());
const successValues = [];
facebookLoginAPI().then((facebookAuthResult) => {
successValues.push(facebookAuthResult.accessToken);
return getFacebookInfoAPI(facebookAuthResult.accessToken);
}).then((facebookProfile) => {
successValues.push(serverAuthToken);
dispatch(authSuccess(...successValues));
}).catch((error) => {
dispatch(authFailure(error));
setTimeOut(() => {
dispatch(authFailureRemove());
}, 4000);
});
};
}
The facebook API :
import {
LoginManager,
AccessToken,
GraphRequest,
GraphRequestManager,
} from 'react-native-fbsdk';
const facebookParams = 'id,name,email,picture.width(100).height(100)';
export function facebookLoginAPI() {
return new Promise((resolve, reject) => {
LoginManager.logInWithReadPermissions(['public_profile', 'user_friends', 'email'])
.then((FBloginResult) => {
if (FBloginResult.isCancelled) {
throw new Error('Login cancelled');
}
if (FBloginResult.deniedPermissions) {
throw new Error('We need the requested permissions');
}
return AccessToken.getCurrentAccessToken();
console.log(FBloginResult);
})
.then((result) => {
resolve(result);
})
.catch((error) => {
reject(error);
});
});
}
export function getFacebookInfoAPI() {
return new Promise((resolve, reject) => {
const profileInfoCallback = (error, profileInfo) => {
if (error) reject(error);
resolve(profileInfo);
};
const profileInfoRequest =
new GraphRequest(
'/me',
{
parameters: {
fields: {
string: facebookParams,
},
},
},
profileInfoCallback
);
new GraphRequestManager().addRequest(profileInfoRequest).start();
});
}
export function getFacebookFriends() {
return new Promise((resolve, reject) => {
const profileInfoCallback = (error, profileInfo) => {
if (error) reject(error);
console.log(profileInfo);
resolve(profileInfo);
};
const profileFriendsRequest =
new GraphRequest(
'/me/friends',
{
parameters: {
fields: {
string: facebookParams,
},
},
},
profileInfoCallback
);
new GraphRequestManager().addRequest(profileFriendsRequest).start();
});
}
The Button for login :
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { View } from 'react-native';
import { bindActionCreators } from 'redux';
import { facebookLogin } from '../../actions/auth';
import { Button } from '../common';
import FBSDK, { LoginManager } from 'react-native-fbsdk';
class Login extends Component {
componentWillMount() {
this.authCheck(this.props.authToken);
}
componentWillReceiveProps(nextProps) {
this.authCheck(nextProps.authToken);
}
authCheck(authToken){
if (authToken) {
return authToken;
}
}
renderError() {
if(this.props.authError){
console.log(this.props.authError);
}
return null;
}
render() {
return(
<Button onPress={this.props.onLoginPressed}> Login with facebook </Button>
);
}
}
export default Login;
And the AuthContainer :
import React, { Component, PropTypes } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { facebookLogin } from '../actions/auth';
import Login from '../components/Login';
class AuthContainer extends Component {
onLoginPressed() {
this.props.actions.facebookLogin();
console.log(this.props);
}
render(){
console.log(this.props);
return (
<Login {...this.props} onLoginPressed={this.onLoginPressed.bind(this)} />
);
}
}
AuthContainer.propTypes = {
welcomeText: PropTypes.string,
authenticating: PropTypes.bool.isRequired,
authToken: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.string,
]),
authError: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.string,
]),
actions: PropTypes.shape({
facebookLogin: PropTypes.func.isRequired,
}).isRequired,
};
function mapStateToProps(state) {
return {
authenticating: state.auth.authenticating,
authToken: state.auth.authToken,
authError: state.auth.authError,
loginText: state.auth.loginText,
};
console.log(state);
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({ facebookLogin }, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(AuthContainer);
and the App.js :
import React, { Component } from 'react';
import { Text, View, AsyncStorage } from 'react-native';
import { createStore, compose, applyMiddleware } from 'redux';
import { connect, Provider } from 'react-redux';
import { persistStore } from 'redux-persist';
import thunkMiddleware from 'redux-thunk';
import reducers from './reducers';
import { Header, Card, CardSection } from './components/common';
import AuthContainer from './containers/AuthContainer';
const store = compose(
applyMiddleware(thunkMiddleware)
)(createStore)(reducers);
persistStore(store, { storage: AsyncStorage });
class App extends Component {
render() {
return(
<Provider store={store}>
<View>
<Header headerText="Kiwee" />
<Card>
<CardSection>
<AuthContainer />
</CardSection>
</Card>
</View>
</Provider>
);
}
}
export default App;
Does someone could help me ? It's really important for me to do that, and I passed 1 month searching for a solutions without any responses ..

try to remove .push() function from your reducers as it is mutating operation.Try to use concat or spread operator. like try replacing
successValues.push(facebookAuthResult.accessToken);
with
[...successValues, ..facebookAuthResult.accessToken]
it is something related to Immutability, you can check about that in redux tutorial or may find on google (I am not in good position to explain that behavior right now)

Related

How to Get createAsyncThunk In The Correct Way Data React Native

I am a new in react native Redux Newest Documentation. I want to use createAsyncThunk
to get my api data using Axios.
Below my code :
App.js
import React, { useState } from 'react';
import { Provider } from 'react-redux';
import { configureStore } from '#reduxjs/toolkit';
import ApiChartingSlice from './redux/slice/api/ApiChartingSlice';
import LoginNavigator from './navigation/LoginNavigator';
const store = configureStore({
reducer: {
ApiChartingMenu: ApiChartingSlice
}
});
export default function App() {
return (
<Provider store={store}>
<LoginNavigator />
</Provider>
);
}
ApiChartingAxios.js
import axios from "axios";
import { BasicAuthUsername, BasicAuthPassword } from "../utility/utility";
export default axios.create({
baseURL: 'https://blablabla.id/index.php',
headers: {
auth: {
username: BasicAuthUsername,
password: BasicAuthPassword
}
}
});
SubApiChartingAxios.js
import ApiChartingAxios from "../ApiChartingAxios";
export const SubApiChartingMenu = async () => {
const response = await ApiChartingAxios.get('/ApiChartingMenu',{
params: null
});
return response;
};
ApiChartingSlice.js
import { createAsyncThunk, createSlice } from '#reduxjs/toolkit'
import { SubApiChartingMenu } from '../../../api/subapi/SubApiChartingAxios';
export const ApiChartingMenuThunk = createAsyncThunk(
'ApiChartingMenu',
async () => {
const response = await SubApiChartingMenu();
console.log(response);
return response.data.Data;
}
)
// status: 'idle' | 'loading' | 'succeeded' | 'failed',
const ApiChartingMenuSlice = createSlice({
name: 'ApiChartingMenu',
initialState: {
apiData: {},
status: 'idle',
error: null
},
reducers: {},
extraReducers: {
[ApiChartingMenuThunk.pending.type]: (state, action) => {
state.playerList = {
status: "loading",
apiData: {},
error: {},
};
},
[ApiChartingMenuThunk.fulfilled.type]: (state, action) => {
state.playerList = {
status: "idle",
apiData: action.payload,
error: {},
};
},
[ApiChartingMenuThunk.rejected.type]: (state, action) => {
state.playerList = {
status: "idle",
apiData: {},
error: action.payload,
};
},
}
});
export default ApiChartingMenuSlice.reducer;
And the last is my screen output:
ChartScreen.js
import { useNavigation } from '#react-navigation/native';
import React, { useEffect, useState, useCallback } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, KeyboardAvoidingView, TextInput, Button } from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import { ApiChartingMenuSlice, ApiChartingMenuThunk } from '../../redux/slice/api/ApiChartingSlice';
const ChartScreen = () => {
console.log('ChartScreen');
const dispatch = useDispatch();
console.log(dispatch(ApiChartingMenuThunk()));
const chartData = useSelector(state => state.ApiChartingMenu.apiData);
console.log(chartData);
return (
<View>
<Button title="test" onPress={() => {}} />
<ChartComponent />
</View>
);
};
export default ChartScreen;
Problem:
I don't know why in my ChartScreen.js this line : console.log(dispatch(ApiChartingMenuThunk()));
return :
Promise {
"_U": 0,
"_V": 0,
"_W": null,
"_X": null,
"abort": [Function abort],
"arg": undefined,
"requestId": "oqhkA7eyL_VV_ea4FDxr3",
"unwrap": [Function unwrap],
}
But in ApiChartingSlice.js in this line console.log(response);
return the correct value.
So, what is the correct way to retrive the value from the createAsyncThunk from my ChartScreen.js
The Api content is a list menu.
I want when first open the apps It execute the redux and show all my list menu.
But now just try to console.log the ApiChartingMenuThunk in ApiChartingSlice.js is not working.
Can anybody solve and guide me to a solution ? Thank You
I figured it out myself the problem is on this file :
ApiChartingSlice.js
and this line should be :
[ApiChartingMenuThunk.fulfilled.type]: (state, action) => {
state.playerList = {
status: "idle",
apiData: state.apiData.push(action.payload),
error: {},
};
also you need to dispatch using this code :
in file ChartScreen.js
this is how we dispatch it.
const toggleGetMenuHandler = useCallback(() => {
dispatch(ApiChartingMenuThunk())
.unwrap()
.then((originalPromiseResult) => {
// console.log(originalPromiseResult);
})
.catch((rejectedValueOrSerializedError) => {
console.log(rejectedValueOrSerializedError);
})
}, [dispatch]);
useEffect(() => {
toggleGetMenuHandler();
}, [toggleGetMenuHandler]);
},
Now this code : const chartData = useSelector(state => state.ApiChartingMenu.apiData);
will have a correct data.

Invariant Violation : Invalid Hooks Call. Hooks Call can only be made inside body of function components

Hi am getting this error at Connect() function in LoginScreen.js. On commenting it its working fine. I am guessing either my Store is not properly setup or i am not able to connect LoginScreen Component to Redux Store.
LoginScreen.js
import React, { Component } from "react";
import PhoneInput from "react-native-phone-input";
import { connect } from "react-redux";
import { View, StatusBar } from "react-native";
import { Container, Item, Input, Button, Text } from "native-base";
import {
phoneChanged,
codeChanged,
onCodeDispatched,
onPhoneLogin,
clearAuth,
onSignOut
} from "../Actions/AuthActions";
//import firebase from "react-native-firebase";
import { auth } from "../Config/firebase";
export class LoginScreen extends Component {
}
export default connect(
null, // passing null just for testing
null
)(LoginScreen);
Store.js
import ReduxThunk from "redux-thunk";
import { createStore, applyMiddleware, compose } from "redux";
import reducer from "../Reducers/index";
let composeEnhancers = compose;
/* eslint no-undef: 0 */
if (__DEV__) {
/* eslint no-underscore-dangle: 0 */
composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
}
const store = createStore(
reducer,
{},
composeEnhancers(applyMiddleware(ReduxThunk))
);
export { store };
AuthReducer.js
import {
LOGIN_FAIL,
LOGIN_SUCCESS,
LOGIN_USER,
PHONE_CHANGED,
CODE_SENT_ERROR,
CODE_CHANGED,
CODE_DISPATCHED,
LOGIN_USER_PHONE,
CODE_SENT,
CODE_NOT_CONFIRMED,
LOGOUT,
SET_USER_OBJECT,
CLEAR_AUTH
} from "../Actions/ActionTypes";
const INITIAL_STATE = {
phone: "+30",
user: null,
message: "",
loading: false,
codeInput: "",
confirmResult: null
};
const AuthReducer = (state = INITIAL_STATE, action) => {
console.log(action);
switch (action.type) {
case PHONE_CHANGED:
return {
...state,
phone: action.payload
};
case CODE_CHANGED:
return {
...state,
codeInput: action.payload
};
case LOGIN_USER:
return {
...state,
loading: true,
message: ""
};
case LOGIN_USER_PHONE:
return {
...state,
loading: true,
message: "Sending code...",
phone: action.payload
};
case CODE_DISPATCHED:
return {
...state,
loading: true,
message: ""
};
case CODE_SENT:
return {
...state,
loading: true,
message: "Code has been sent!",
confirmResult: action.payload
};
case CODE_SENT_ERROR:
return {
...state,
loading: false,
message: `Sign in with Phone number error: ${action.payload}`,
confirmResult: null
};
case SET_USER_OBJECT:
return {
...state,
user: action.payload
};
case CODE_NOT_CONFIRMED:
return {
...state,
message: `Code confirmation error: ${action.payload}`
};
case LOGIN_SUCCESS:
return {
...INITIAL_STATE,
user: action.payload,
message: "login Success"
};
case LOGIN_FAIL:
return {
...state,
message: "Authentication Failed.",
loading: false,
password: "",
phone: "+91"
};
case LOGOUT:
return {
...state,
message: "",
user: null
};
case CLEAR_AUTH:
return {
...state,
...INITIAL_STATE
};
default:
return state;
}
};
export default AuthReducer;
Root.js
import React from "react";
import { Provider } from "react-redux";
import { Navigator } from "./Navigation/Index";
import { store } from "./Store/Index";
export default class Root extends React.Component {
render() {
return (
<Provider store={store}>
<Navigator />
</Provider>
);
}
}
AuthActions.js
//import { firebase } from "react-native-firebase";
import * as actionTypes from "./ActionTypes";
import { auth } from "../Config/firebase";
const phoneChanged = text => {
return {
type: actionTypes.PHONE_CHANGED,
payload: text
};
};
const onLoginSuccess = (dispatch, user) => {
dispatch({
type: actionTypes.LOGIN_SUCCESS,
payload: user
});
};
const signOut = dispatch => {
dispatch({
type: actionTypes.LOGOUT
});
};
const onPhoneLogin = phone => {
return dispatch => {
dispatch({
type: actionTypes.LOGIN_USER_PHONE
});
auth
.signInWithPhoneNumber(phone)
// sign in success
.then(confirmResult => {
onCodeSent(dispatch, confirmResult);
})
// sign in error
.catch(error => onCodeSentError(dispatch, error));
};
};
const codeChanged = text => {
return {
type: actionTypes.CODE_CHANGED,
payload: text
};
};
const onCodeSent = (dispatch, confirmResult) => {
dispatch({
type: actionTypes.CODE_SENT,
payload: confirmResult
});
};
const onCodeConfirmError = (dispatch, error) => {
dispatch({
type: actionTypes.CODE_NOT_CONFIRMED,
payload: error
});
};
const onCodeDispatched = code => {
return (dispatch, getState) => {
getState()
.auth.confirmResult.confirm(code)
.then(user => onLoginSuccess(dispatch, user))
.catch(error => onCodeConfirmError(dispatch, error));
};
};
const onCodeSentError = (dispatch, error) => {
dispatch({
type: actionTypes.CODE_SENT_ERROR,
payload: error
});
};
const onSignOut = () => {
return dispatch => {
auth
.signOut()
.then(() => signOut(dispatch))
.catch(error => console.log(error));
};
};
const clearAuth = () => {
return dispatch => {
dispatch({
type: actionTypes.CLEAR_AUTH
});
};
};
export {
onSignOut,
clearAuth,
codeChanged,
onPhoneLogin,
phoneChanged,
onCodeDispatched
};
The Idea is basically to call LoginScreen which is part of 'Auth' StackNavigator and Render PhoneNumberInput and OTP.
React-redux (> 7.0.1) uses hook & React-native (< 0.59) doesn’t support Hooks yet.
You can run npm ls react-native in your application folder to check which version you’re using.
If you find more than one of them, this might also create problems. more on it
There are two solution
Upgrade the react native version to 0.59.0
OR
Downgrade the react redux version to 6.0.1
I hope it help you.

How to fix redux authentication in react-native-navigation?

I am creating redux authentication with react-native-navigation. It has two layouts which is switching by store auth state. When I am starting application in xCode simulator and trying to authenticate, it does not change a Auth layout to Main. But when I'm start Safari console to see messages from application, auth works fine and layout is changing. Please explain to me why this is happening?
index.js
import React, { Component, } from 'react';
import { Navigation, } from 'react-native-navigation';
import { Provider, } from 'react-redux';
import store from './src/store';
import registerScreens from './src/screens';
registerScreens(store, Provider);
export default class App {
constructor () {
this.auth = false;
store.subscribe(this.onStoreUpdate.bind(this));
this.start();
}
onStoreUpdate () {
const state = store.getState();
// if I'am write alert(state.auth) here, it show me false
if (this.auth != state.auth) {
this.auth = state.auth;
this.start();
}
}
start () {
switch (this.auth) {
case false:
Navigation.startTabBasedApp({
tabs: [{
screen: 'navigation.AuthScreen',
}, {
screen: 'navigation.RegisterScreen',
},],
});
break;
case true:
Navigation.startSingleScreenApp({
screen: {
screen: 'navigation.MainScreen',
},
});
break;
}
}
}
const application = new App();
auth.screen.js
import React, { PropTypes, Component, } from 'react';
import { ... } from 'react-native';
import { bindActionCreators, } from 'redux';
import { connect, } from 'react-redux';
import * as actions from './../actions';
class AuthScreen extends Component {
constructor (props) {
super(props);
this.handlePressEnter = this.handlePressEnter.bind(this);
}
handlePressEnter () {
// if I'am commenting line bellow and line in last then((), auth works fine
this.props.actions.request(true);
jsonFetch(url, {}).then((value) => {
return this.props.actions.auth(true);
}).catch((errors) => {
console.log(errors);
}).then(() => {
/* * */
this.props.actions.request();
});
}
render () {
....
}
}
function mapStateToProps (state, ownProps) {
return {
loading: state.loading,
};
}
function mapDispatchToProps (dispatch) {
return {
actions: bindActionCreators(actions, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps) (AuthScreen);
actions/index.js
import * as constants from './../constants';
export const request = (state = false) => {
return {
type: constants.REQUEST,
payload: {
state,
},
};
}
export const auth = (state = false) => {
return {
type: constants.AUTH,
payload: {
state,
},
};
}
reducers/index.js
import { combineReducers, } from 'redux';
import * as constants from './../constants';
const loading = (state = false, action) => {
switch (action.type) {
case constants.REQUEST:
return action.payload.state;
default:
return state;
}
}
const auth = (state = false, action) => {
switch (action.type) {
case constants.AUTH:
return action.payload.state;
default:
return state;
}
}
const reducers = combineReducers({
loading,
auth,
});
export default reducers;
store.index.js
import { createStore, applyMiddleware, } from 'redux';
import thunkMiddleware from 'redux-thunk';
import { createLogger, } from 'redux-logger';
import reducers from './../reducers';
const loggerMiddleware = createLogger();
const store = createStore(reducers, applyMiddleware(thunkMiddleware, loggerMiddleware));
export default store;

Fetch data is empty in componentwillMount in react native redux

Hello I'm trying to learn react native from Stephen Grider's react-native course.I'm stuck to load data from my webservice and list them by using redux and lodash .I can successfully get data and can see it in render (console.log) ,and but my props always is null in componentDidUpdate or componentWillMount .
Any help is appreciated,thanks.
Reducer is like this;
import { TEST_FETCH, TEST_LOAD } from "../actions/types";
const INITIAL_STATE = { dataSource: [] };
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case TEST_FETCH:
return { ...state, loading: false, dataSource: action.payload.data };
case TEST_LOAD:
return { ...state, loading: true, error: "" };
default:
return state;
}
};
and action is ;
import { TEST_LOAD, TEST_FETCH } from "./types";
export const getdata = ( ) => {
return dispatch => {
dispatch({ type: TEST_LOAD });
fetch("http://myserver/getdata", {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
}
})
.then(response => {
return response.json();
})
.then(responseData => {
return responseData;
})
.then(data => {
// return data;
dispatch({ type: TEST_FETCH, payload: data });
});
};
};
and page is ;
import _ from 'lodash';
import React, { Component } from "react";
import { View, Text, ListView } from "react-native";
import { connect } from "react-redux";
import { getdata } from "../actions";
class testList extends Component {
componentWillMount() {
this.props.getdata();
}
componentDidMount() {
console.log(this.props.myarray ); // myarray is empty
this.createDataSource(this.props.myarray);
}
componentDidUpdate() {
console.log(this.props.myarray ); // I tried this but still myarray is empty
this.createDataSource(this.props.myarray);
}
createDataSource({ dtsource }) {
// sure dtsource is null too
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2});
this.dataSource = ds.cloneWithRows(dtsource);
}
render() {
console.log(this.props.myarray); // if I write here,I can see my json's output
return <View>
<Text>Employee List</Text>
<ListView dataSource={this.props.myarray} renderRow={rowData => <Text
>
{rowData}
</Text>} />
</View>;
}
}
const mapStateToProps = state => {
const myarray= _.map(state.testForm.dataSource, function(v) {
return { ...v };
});
return { myarray};
};
export default connect(mapStateToProps , { getdata })(testList);
I would recommend you to use a FlatList since ListView is deprecated and has bad performance. In the meantime, you can use the code snippet below to pass the correct object to dataSource. You might need to add some null checks depending on the state of the data you pass to myarray.
import _ from 'lodash';
import React, { Component } from "react";
import { View, Text, ListView } from "react-native";
import { connect } from "react-redux";
import { getdata } from "../actions";
class testList extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2}).cloneWithRows(props.myarray ? props.myarray : [])
};
}
componentDidMount() {
this.props.getdata();
}
componentDidUpdate() {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(props.myarray ? props.myarray : [])
});
}
render() {
return <View>
<Text>Employee List</Text>
<ListView dataSource={this.props.myarray} renderRow={rowData => <Text
>
{rowData}
</Text>} />
</View>;
}
}
const mapStateToProps = state => {
const myarray = _.map(state.testForm.dataSource, function(v) {
return { ...v };
});
return { myarray};
};
export default connect(mapStateToProps , { getdata })(testList);

React native redux props not updated after calling an action

I'm new to react, react native, and redux, I have a react native app that has this login in render
render() {
return (<TouchableOpacity style={Style.btnSubmit} onPress={this.onLoginPressed.bind(this)}>
<Text style={Style.btnText}>Login</Text>
</TouchableOpacity>)
}
and the onLoginPressed function is here
onLoginPressed() {
const { username, password } = this.props.form;
this.props.login({ username, password}); // the login is using the fetch api
// props are not updated with the new state values
console.log(this.props)
}
Everything is working correctly but
the props doesn't update in the onLoginPressed function, however, when I console log the props inside the render function, it's updated.
I understand that redux do a full rendering, but I just don't really understand if it should update the props after calling the login.
Thank you
Update
Here is the end of the component
function mapStateToProps(state) {
return {
...state.login
}
}
function mapDispatchToProps(dispatch) {
return {
login: (formData) => dispatch(login(formData)),
facebookLogin: (formData) => dispatch(facebookLogin(formData)),
setUsername: (username) => dispatch(setUsername(username)),
setPassword: (password) => dispatch(setPassword(password)),
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Login);
here is the action
import { Host, Endpoints } from '../config/server';
import { loginActions } from '../config/constants';
/*
* state props
- form
- inProgress
- error
- data
*/
export function login(form) {
return (dispatch) => {
dispatch(loggingIn(true));
fetch(Host + Endpoints.auth.login, {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(form)
})
.then(res => res.json())
.then(res => {
dispatch(loggingIn(false));
res.error ? dispatch(loginError(res.error)) :
dispatch(loginSuccess(res.data));
})
.catch(err => dispatch(loginError(err)));
}
}
export function facebookLogin(data) {
return (dispatch) => {
dispatch(loggingIn());
fetch(Host + Endpoints.auth.facebookLogin, {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(data)
})
.then(res => res.json())
.then(data => dispatch(loginSuccess(data)))
.catch(err => dispatch(loginError(err)));
}
}
export function setUsername(username) {
return {
type: loginActions.setUsername,
username
}
}
export function setPassword(password) {
return {
type: loginActions.setPassword,
password
}
}
function loginSuccess(data) {
return {
type: loginActions.LoginSuccess,
data
}
}
function loginError(error) {
return {
type: loginActions.LoginError,
error
}
}
function loggingIn(val) {
return {
type: loginActions.LoggingIn,
inProgress: val
}
}
and here is the reducer
import { loginActions } from '../config/constants';
const initialState = {
form: {
username: '',
password: ''
},
data: null,
inProgress: false,
error: null
};
export default function loginReducer(state = initialState, action) {
switch(action.type) {
case loginActions.LoggingIn:
return {
...state,
inProgress: action.inProgress
}
case loginActions.LoginError:
return {
...state,
error: action.error,
}
case loginActions.LoginSuccess:
return {
...state,
inProgress: false,
error: null,
data: action.data
}
case loginActions.setUsername:
return {
...state,
form: {
username: action.username,
password: state.form.password
}
}
case loginActions.setPassword:
return {
...state,
form: {
username: state.form.username,
password: action.password
}
}
default:
return {
...state
}
}
}
and the reducer index file
import { combineReducers } from 'redux';
import login from './login';
const rootReducer = combineReducers({
login
});
export default rootReducer;
and the configureStore file
import { createStore, applyMiddleware } from 'redux'
import reducers from './reducers'
import thunk from 'redux-thunk'
export default function configureStore() {
let store = createStore(reducers, applyMiddleware(thunk))
return store
}
of course the root is wrapped with the provider passing the store.
You are doing console.log in the same function call that dispatch the login actions. That won’t work, because JavaScript is non-blocking, it will not wait for the login action to complete and update the props before calling console.log
Try console.log in something like componentWillReceiveProps.