问题
Where exactly should I deal with the problem of this component not loading with the desired state?
My render method causes the following error...
Uncaught TypeError: Cannot read property 'email' of undefined
...even though the JSON.stringify line shows me that the email property does (eventually) exist.
The console.log down in mapStateToProps confirms that state loads first without the any user property (thus causing the error).
Behold my naive attempt to resolve this in my constructor method. It's not working.
What is the right way to deal with this situation? Some conditional inside the render method? Tried that too but still no luck.
import React, {Component, PropTypes} from 'react';
import {connect} from 'react-redux';
import * as actions from '../actions';
class Feature extends Component {
constructor(props){
super(props);
this.state = {
'auth': {
'user':{
email:'',
id:''
}
}
}
}
componentWillMount() {
this.props.fetchMessage(); // puts the user object into state
}
render() {
return (
<div className="feature">
Here is your feature
{JSON.stringify(this.props.user , null, 2)}
{this.props.user.email}
</div>
);
}
}
function mapStateToProps(state) {
console.log('state',state);
return { user: state.auth.user }
}
export default connect(mapStateToProps, actions)(Feature);
/////////// action /////////
export function fetchMessage(){
return function(dispatch){
axios
.get(ROOT_URL, {
headers: {
authorization: localStorage.getItem('token')
}
})
.then((response) => {
dispatch({
type: FETCH_MESSAGE,
payload: response.data.user
})
})
}
}
///////////////// reducer /////////////
var authReducer = (state={}, action) => {
console.log('action.payload',action.payload);
switch(action.type){
case AUTH_USER: return {...state, error: '', authenticated: true};
case UNAUTH_USER: return {...state, error: '', authenticated: false};
case AUTH_ERROR: return {...state, error: action.payload};
case FETCH_MESSAGE: return {...state, user: {
email: action.payload.email,
id: action.payload._id
}};
default: return state;
};
};
回答1:
Redux uses a global state called store that lives outside your component.
Inside your constructor you have a this.state = {...} statement. This is a local state that is only available to the Feature component.
connect from react-redux basically connects the info inside the store to your component props hence called mapStateToProps.
Edit your mapStateToProps to something like...
function mapStateToProps(state) {
const { auth: { user = {} } = {}} = state;
return {
user
}
}
What it does is try to extract the user property from the store and if it doesn't exist yet, set it to empty object. Your error is due to your mapStateToProps accessing the user property that doesn't exist yet. You might want to set a default value as your initialState to avoid this issue.
回答2:
So here is what is happening.. You are making a server request for a user object and on success the received object is stored in your redux store. While performing such an action your component is rendered as follows:
- You have initiated the request to the server, which means currently there is no
userin your store and so the component is rendered withthis.props.userundefined. Your request is successful and the
userobject is stored in your store. When this happensreact-reduxwill re-render your component with the user object andthis.props.useris available in your component.During the first step since
this.props.useris unavailable you are getting an error while accessingthis.props.user.email. Although @jpdelatorre 's answer is pretty good, another thing you can do is simply add a check in your render method.render() { let user = this.props.user || {}; .... {user.email} .... }
来源:https://stackoverflow.com/questions/40733346/how-to-render-properties-of-objects-in-react