简体   繁体   中英

Redux/React: why `this.props` undefined

My codes:

  render() {
    console.log( 'render, state' + Array.isArray(this.props.users) + ',' + JSON.stringify(this.props.users) );
    return (
      <section>
        <div>testing</div>
        <div>{JSON.stringify(this.props.users)}</div>
        <ul>
          {this.props.users.map( user => <li>{user.email}</li>)}
        </ul>
      </section>
    );
  }

Both <div>testing</div> and <div>{JSON.stringify(this.props.users)}</div> work fine (after removing <ul>...</ul> ). But <ul>...</ul> did not work. the error is:

Uncaught TypeError: Cannot read property 'map' of undefined

Any comments welcomed. Thanks

UPDATE

The following codes work fine, this.props.users is an Array, and all the console logs look OK. I just need to know why <ul>{this.props.users.map( user => <li>{user.email}</li>)}</ul> not work. Why this.props.users in <ul>...</ul> is undefined.

  render() {
    console.log( 'render, state' + Array.isArray(this.props.users) + ',' + JSON.stringify(this.props.users) );
    return (
      <section>
        <div>testing</div>
        <div>{JSON.stringify(this.props.users)}</div>
      </section>
    );
  }

the console output of the above codes (only two s):

render, statetrue,[{"_id":"5831e6df511e","updatedAt":"removed","createdAt":"removed","email":"removed","password":"xxxx","__v":0,"role":"xxx","profile":{"firstName":"test","lastName":"tester"}},{...}, {...}]

UPDATE

My codes:

import { connect } from 'react-redux';
import { fetchAllUsers } from '../../actions/index';

class HomePage extends Component {
  componentWillMount() {
    console.log( 'componentWillMount()' );
    this.props.fetchAllUsers();
  }

  render() {
    console.log( 'render(), ' + Array.isArray(this.props.users) + ',' + JSON.stringify(this.props.users) );
    return (
      <section>
        <div>{JSON.stringify(this.props.users)}</div>
      </section>
    );
  }
}

function mapStateToProps(state) {
    console.log( 'state:' + JSON.stringify(state) );// working fine, and the console.log is OK. not added to this post
    return  {
        users: state.admin.users
    }
}

export default connect(mapStateToProps, {fetchAllUsers})(HomePage);

console.log (some details in the User objects removed.):

render(), true,[{"_id":"5831","profile":{"firstName":"test","lastName":"tester"}},{"_id":"5831e874cedf511f", "profile":{"firstName":"cccc","lastName":"cc"}},{"_id":"5831120","profile":{"firstName":"cccccccc","lastName":"ccc"}}]

And, on the webpage, the string of this.props.users is shown.

My question is why <ul>{this.props.users.map( user => <li>{user.email}</li>)}</ul> not work, but <div>{JSON.stringify(this.props.users)}</div> working fine.

I think I already described my questions clearly. If more information needed, please tell me.

More details

my admin_reducer.js

import { FETCH_ALL_USERS } from '../actions/types';

const INITIAL_STATE = { users:[] };

export default function (state = INITIAL_STATE, action) {
  console.log( 'users is action.payload:'+JSON.stringify( { users:action.payload } ) );
  return Object.assign( {}, state, {users:action.payload});
  //return { ...state, users:action.payload };
}

my index.js

import adminReducer from './admin_reducer';

const rootReducer = combineReducers({
  ...
  admin: adminReducer
});

export default rootReducer;

my action.js
export function fetchAllUsers() {
  return function(dispatch) {
    axios.get(`${API_URL}/user/all`)
    .then(response => {
      dispatch({
        type: FETCH_ALL_USERS,
        payload: response.data
      });
    })
    .catch(response => dispatch(errorHandler(response.data.error)))
  }
}

UPDATE

why console log of console.log(this.props.users) is [object Object],[object Object],[object Object] ?

First of, according to react docs , async requests should be made inside the componentDidMount method.

Secondly, to make sure that you're not trying to map an un-initialized array, use this:

<ul>{(this.props.users || []).map( user => <li>{user.someProperty}</li> )}</ul>

This should cover it in case you forgot to initialize the array for some reason.

You can call this without error..

JSON.stringify(this.props.users)

...because it just outputs "undefined"). That is valid. However, if you try to call a method on the undefined that was returned, of course that fails...

// Following tries to call undefined.map(), which is of course wrong
this.props.users.map( user => <li>{user.email}</li>)

Common shorthand to address your scenario uses a "short-circuit operator" (like a quickie "if (is true)")...

<ul>{this.props.user && this.props.users.map( user => <li>{user.email}</li>)}</ul>

^^ Note the "this.props.user && ", which prevents the following this.props.user.map() from being called if this.props.user is null or undefined

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM