React native redux after login statetoprops not updating before render - react-native

After login and redirecting to Home page component here I am calling:
mapStateToProps = (state) => ({
getUser: state.userReducer.getUser
});
And trying to render the value:
render() {
const {getUser: {userDetails}} = this.props;
return(
<View><Text>{userDetails.EmployeeID}</Text></View>
)
}
USER Reducer
import { combineReducers } from 'redux';
const getUser = (state = {}, action) => {
switch (action.type) {
case "GET_USER_LOADING":
return {
isLoading: true,
isError: false,
isSuccess: false,
userDetails: null,
errors: null
}
case "GET_USER_SUCCESS":
return {
isLoading: false,
isError: false,
isSuccess: true,
userDetails: action.payload,
errors: null
}
case "GET_USER_FAIL":
return {
isLoading: false,
isError: true,
isSuccess: false,
userDetails: null,
errors: action.payload
}
default:
return state;
}
}
export default combineReducers({
getUser
});
And loginuser action
export const loginUser = (payload) => {
return async (dispatch) => {
try {
dispatch({
type: "LOGIN_USER_LOADING"
});
const response = await fetchApi("front/authentication/login", "POST", payload, 200);
if(response.responseBody.status) {
dispatch({
type: "LOGIN_USER_SUCCESS",
});
dispatch({
type: "AUTH_USER_SUCCESS",
token: response.token
});
dispatch({
type: "GET_USER_SUCCESS",
payload: response.responseBody.data
});
return response.responseBody.status;
} else {
throw response;
}
} catch (error) {
dispatch({
type: "LOGIN_USER_FAIL",
payload: error.responseBody
});
return error;
}
}
}
But getting an error:
TypeError: Undefined is not an object(Evaluating 'userDetails.EmployeeID'
If I Remove the userDetails.EmployeeID and navigate to next page and then come back it show the EmployeeID fine.

Try this way,
render() {
const {getUser} = this.props;
return(
<View><Text>{getUser.userDetails.EmployeeID}</Text></View>
)}
if that doesn't work, kindly post redux code

If your initial state resolves to something "falsy" for userDetails you can "wait" for its value:
render() {
const {getUser: {userDetails}} = this.props;
return <View>
<Text>{userDetails ? userDetails.EmployeeID : 'Loading'}</Text>
</View>
}

Related

TypeError: undefined is not an object (evaluating 'state.postcomics.postscomics')

I'm starting on React-Native, (and sorry for my English too).
After several researches, I cannot find the solution of this problem.
And I can't really understand this problem.
import { connect } from 'react-redux';
import ListComics from '../components/ListComics';
import { fetchPostscomics } from "../action/comics";
const mapStateToProps = state => {
return {
comics: state.postcomics.postscomics,
//loading: state.postcomics.loading
};
};
const mapDispatchToProps = dispatch => {
return {
fetchPostscomics: () => dispatch(fetchPostscomics()),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(ListComics);
reducer:
``
import {
FETCH_POSTSCOMICS_REQUEST,
FETCH_POSTSCOMICS_SUCCESS,
FETCH_POSTSCOMICS_FAILURE
} from '../action/comics';
import {
ADD_POSTCOMICS_REQUEST,
ADD_POSTCOMICS_SUCCESS,
ADD_POSTCOMICS_FAILURE,
} from '../action/addComics';
const initialState = {
comics: []
};
function postcomics(state = initialState, action) {
switch(action.type) {
case FETCH_POSTSCOMICS_REQUEST:
return { ...state, loading: true };
case ADD_POSTCOMICS_REQUEST:
return { ...state, loading: true };
case FETCH_POSTSCOMICS_SUCCESS:
return {
...state,
comics: action.payload,
loading: false
};
case ADD_POSTCOMICS_SUCCESS:
return { comics: [...state.postscomics, action.payload]};
case FETCH_POSTSCOMICS_FAILURE:
return { ...state, error: action.payload, loading: false };
case ADD_POSTCOMICS_FAILURE:
return { ...state, error: action.payload, loading: false };
default:
return state;
}
}
const store = combineReducers({postcomics});
export default createStore(store, applyMiddleware(thunk));
``
`Code FectchPostscomics:
export const FETCH_POSTSCOMICS_REQUEST = 'FETCH_POSTSCOMICS_REQUEST';
export const FETCH_POSTSCOMICS_SUCCESS = 'FETCH_POSTSCOMICS_SUCCESS';
export const FETCH_POSTSCOMICS_FAILURE = 'FETCH_POSTSCOMICS_FAILURE';
export function fetchPostscomics() {
return function (dispatch) {
dispatch(fetchPostscomicsRequest());
console.log(process.env.API_URL);
return fetch('http://192.168.1.23:4000/comics')
.then(
response => response.json(),
error => dispatch(fetchPostscomicsFailure(error))
)
.then(postscomics => {
dispatch(fetchPostscomicsSuccess(postscomics));
});
}
}
export function fetchPostscomicsRequest() {
return {type: FETCH_POSTSCOMICS_REQUEST};
}
export function fetchPostscomicsSuccess(posts) {
return {type: FETCH_POSTSCOMICS_SUCCESS, payload: { comics: postscomics} };
}
export function fetchPostscomicsFailure(error) {
return {type: FETCH_POSTSCOMICS_FAILURE, payload: error};
}
Youy action.payload is an object ... and you need to pass only comics to your state ... not the whole object
case FETCH_POSTSCOMICS_SUCCESS:
return {
...state,
...action.payload,
loading: false
};
OR
case FETCH_POSTSCOMICS_SUCCESS:
return {
...state,
comics: action.payload.comics,
loading: false
};
And regarding accessing your comics state:
const mapStateToProps = state => {
return {
comics: state.postcomics.comics // <-- Look at this
};
};
Same thing for other actions like ADD_POSTCOMICS

useDispatch() and useSelector() are not wroking in hooks react native?

I am moving from classes to hooks in react native but facing some issues using redux with hooks.
My work till now
Login.js
const Login = props => {
const {navigation} = props;
const dispatch = useDispatch();
const {success, loading, error} = useSelector(state => state.auth);
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const onLoginPress = async () => {
await dispatch(login(email, password)); //here VSCode give hints await is useless ? Why ? how to use await then ?
if (success) {
navigation.navigate('Home');
} else {
alert(error || 'Invalid Credentials. Please Try again');
}
};
//other code
export default Login;
I am dispatching login action when user presses login button. But problem is app stucks here and action doesn't complete and always remains auth_loading
my login action
export const login = (email, pass) => {
return async dispatch => {
dispatch(authLoading());
try {
const res = await firebaseService
.auth()
.signInWithEmailAndPassword(email, pass); //here app action stucks
dispatch(loginSuccess(res));
} catch (err) {
dispatch(authFailed(err.message));
}
};
};
My reducer
import {
LOGIN_EMAIL_CHANGED,
LOGIN_PASS_CHANGED,
LOGIN_SUCCESS,
REGISER_SUCCESS,
} from '../types';
import {AUTH_FAILED, AUTH_LOADING} from '../actions/AuthActions';
const initialState = {
loginEmail: null,
loginPass: null,
loading: false,
success: false,
user: null,
error: '',
authenticated: false,
};
export const AuthReducer = (state = initialState, action) => {
switch (action.type) {
case LOGIN_EMAIL_CHANGED:
return {
...state,
loginEmail: action.payload,
};
case LOGIN_PASS_CHANGED:
return {
...state,
loginPass: action.payload,
};
case AUTH_LOADING: {
return {
...state,
success: false,
loading: true,
error: '',
};
}
case AUTH_FAILED: {
return {
...state,
loading: false,
success: false,
error: action.payload,
};
}
case LOGIN_SUCCESS: {
return {
...state,
user: action.payload,
loading: false,
success: true,
error: null,
};
}
case REGISER_SUCCESS: {
return {
...state,
user: action.payload,
loading: false,
success: true,
error: null,
};
}
default:
return state;
}
};
Am i using hooks in right way ?
Or how to await after dispatching action in hook. ?
Help will be appreciated.
Thanks

React native mapDispatchToProps not working

I can't get my mapDispatchToProps to work properly.
I export a combineReducers:
export default combineReducers({
auth: AuthReducer,
tenants: TenantsReducer
});
The tenants reducer:
const INITIAL_STATE = {
error: false,
data: [],
tenantData: {},
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case GET_TENANTS_DATA:
return { ...state, error: false, data: action.payload };
case GET_TENANT_DATA:
return { ...state, error: false, tenantData: action.payload };
default:
return state;
}
};
Then I have getTenantByID method in my action
export const getTenantByID = ({ tenantID }) => {
return (dispatch) => {
const getTenant = {
FirstName: 'Jonh', LastName: 'Doe', Email: 'jonh#test.com', Phone: 'xxx-xxx-xxxx',
Unit: '101', MiddleName: '',
};
dispatch({
type: GET_TENANT_DATA,
payload: getTenant
});
};
};
Finally, I tried to use it in my component.
import { connect } from 'react-redux';
import { getTenantByID } from '../actions';
...
componentDidMount() {
const { navigation } = this.props;
const tenantID = navigation.getParam('tenantID', '0');
this.props.getTenantByID(tenantID);
console.log(this.props);
this.state = {
tenantData: this.props.tenantData
};
}
const mapStateToProps = ({ tenants }) => {
return {
error: tenants.error,
tenantData: tenants.tenantData
};
};
const mapDispatchToProps = () => {
return {
getTenantByID
};
};
export default connect(mapStateToProps, mapDispatchToProps)(TenantDetails);
In my componentDidMount, the console.log(this.props) is returning a empty object for tenantData. What am I doing wrong?
Initial state is showing as the component already mounted, which is empty object {}
this.props.getTenantByID(tenantId);
this action triggers actually, but the data is not available in componentDidMount lifecycle.
try putting log in render like this
componentDidMount(){
this.props.getTenantByID(2);
}
render() {
console.log(this.props.tenantData); // 1st render => {}, 2nd render=> desired data
return (
<div/>
);
}
use componentDidUpdate to check if value is changed,
componentDidUpdate(prevProps){
if(prevProps.tenantData !== this.props.tenantData){ console.log(prevProps.tenantData, this.props.tenantData) }
}
remember to receive the dispatch parameter in your mapDispatchToProps method
const mapDispatchToProps = (dispatch) => {
return {
getTenantByID: (tenantID ) => {
dispatch(getTenantByID({tenantID }));
};
};
};
call for
this.props.getTenantByID({ tenantID: 10 })

store.getstate() evaluate to undefined

in a react-native project,I keep hitting in this error:
state is undefined, evaluating store.getstate()
//store.js
const composeEnhancers =
typeof window === "object" && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
: compose;
const enhancer = composeEnhancers(applyMiddleware(thunk));
const Store = createStore(
combineReducers(
{
form: formReducer,
appointmentsReducer
},
enhancer
)
);
console.log(Store.getState());
export default Store;`
//reducer.js
import {
FETCH_APPOINTMENTS_BEGIN,
FETCH_APPOINTMENTS_SUCCESS,
FETCH_APPOINTMENTS_FAILURE
} from '../actions/appointmentsAction';
const initialState = {
data: [],
loading: false,
error: null
};
export default function appointmentsReducer(state = initialState, action) {
switch(action.type) {
case FETCH_APPOINTMENTS_BEGIN:
return {
...state,
loading: true,
error: null
};
case FETCH_APPOINTMENTS_SUCCESS:
return {
...state,
loading: false,
data: action.payload.appointments
};
case FETCH_APPOINTMENTS_FAILURE:
return {
...state,
loading: false,
error: action.payload.error,
data: []
};
default:
return state;
}
}
//actions.js
import { listUrl } from "../cst";
export const FETCH_APPOINTMENTS_BEGIN = "FETCH_APPOINTMENTS_BEGIN";
export const FETCH_APPOINTMENTS_SUCCESS = "FETCH_APPOINTMENTS_SUCCESS";
export const FETCH_APPOINTMENTS_FAILURE = "FETCH_PRODUCTS_FAILURE";
export const fetchAppointmentsBegin = () => ({
type: FETCH_APPOINTMENTS_BEGIN
});
export const fetchAppointmentsSuccess = appointments => ({
type: FETCH_APPOINTMENTS_SUCCESS,
payload: { appointments }
});
export const fetchAppointmentsFailure = error => ({
type: FETCH_APPOINTMENTS_FAILURE,
payload: { error }
});
export function fetchAppointments() {
return dispatch => {
dispatch(fetchAppointmentsBegin());
return fetch(listUrl)
.then(handleErrors)
.then(res => res.json())
.then(json => {
dispatch(fetchApointmentsSuccess(json.appointment));
return json.appointment;
})
.catch(error => dispatch(fetchAppointmentsFailure(error)));
};
}
// Handle HTTP errors since fetch won't.
function handleErrors(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
// app.js
export default function App() {
return (
<Provider store={Store}>
<Navigation />
</Provider>
);
}
//list rendrer component :
const mapStateToProps = state => ({
data: state.appointments.data,
loading: state.loading,
error: state.error
});
the console.log of store.getstate() gives :
Object {
"appointmentsReducer": Object {
"data": Array [],
"error": null,
"loading": false,
},
"form": Object {},
I'm not sure where the problem is.
Is it due to the asynchronous call not being handled properly?
If I use saga to handle the fetch, will it resolve the problem?
Any help would be appreciated .

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.