0

While learning React with Redux just trying to render some user details.

Getting the typical error TypeError: Cannot read property 'map'. I can understand that state.users in the mapStateToProps method is undefined. Tried using the constructor to set the initial state. But no luck. Am I missing something trivial? the error is on return this.props.users.map((user) => { line in createListItems() method.

containers\userList.js

import React, {Component} from 'react';
import bindActionCreators from 'redux';
import {connect} from 'react-redux';

class UserList extends Component{

createListItems(){
         return this.props.users.map((user) => { // here is the error
            return (
                <li key={user.id}>
                    {user.firstName} {user.lastName}
                </li>
            );
        }   );
}

render(){
    return(
        <ul>
            {this.createListItems()}
        </ul>
    );
}
}

function mapStateToProps(state) {
return {
    users: state.users
};
}

export default connect(mapStateToProps)(UserList);

reducers\userReducers.js

export default function () {
return [
    {
        id: 1,
        firstName: "sally",
        lastName: "brown",
        age: 12,
        location: "lund"

    },
    {
        id: 2,
        firstName: "Terance",
        lastName: "Smith",
        age: 23,
        location: "London"

    },
    {
        id: 3,
        firstName: "Petter",
        lastName: "Phantom",
        age: 34,
        location: "Manchester"

    }
]
}

reducers\index.js

import  { combineReducers }  from 'redux';
import UserReducers from './userReducers';

const allReducers = combineReducers({
    users: UserReducers
});

export default allReducers;

src\index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/app';
import registerServiceWorker from './registerServiceWorker';

import { createStore }  from 'redux';
import allReducers from './reducers/userReducers'; 
import { Provider } from 'react-redux';


let store = createStore(allReducers);

ReactDOM.render(
     <Provider store={store}>
        <App />
     </Provider>
, document.getElementById('root'));
registerServiceWorker();
PineCone
  • 2,193
  • 12
  • 37
  • 78
  • 2
    Is this all the code or did you leave stuff out for brevity? I'm not seeing where your reducer is actually setting the state in the store. – sma Sep 11 '17 at 19:40
  • You are not dispatching any action to set your `users` state. Either preload the redux state or dispatch an action to update that state with your `users` state. – Prakash Sharma Sep 11 '17 at 19:42
  • This is all the code I have so far. I haven't used any `Action` yet. Without dispatching an Action is it not possible to load the state till I start using Action? – PineCone Sep 11 '17 at 19:46
  • @shaz Before action you can set initial value of redux state. https://stackoverflow.com/questions/37823132/how-to-set-initial-state-in-redux – Prakash Sharma Sep 11 '17 at 19:49
  • @sma it's in the the src\index.js where I am passing allReducers. Actually found the issue. There was a wrong import for the variable `allReducers` – PineCone Sep 11 '17 at 19:50

2 Answers2

0

The problem is that reducer couldn't set the state to the store hence state.users was undefined.

Wrong import was done for the variable allReducers in the src\index.js file.

incorrect

src\index.js
...
import allReducers from './reducers/userReducers';  

correct

src\index.js
...
import allReducers from './reducers/index'; 
PineCone
  • 2,193
  • 12
  • 37
  • 78
0

I suggest modifying the way you are building your reducers a bit, as follows:

// reducers/users.js

const ADD_USER = 'add.user'

const USERS = [{
  id: 1,
  firstName: "sally",
  lastName: "brown",
  age: 12,
  location: "lund"
}, {
  id: 2,
  firstName: "Terance",
  lastName: "Smith",
  age: 23,
  location: "London"
}, {
  id: 3,
  firstName: "Petter",
  lastName: "Phantom",
  age: 34,
  location: "Manchester"
}]

export default (state = USERS, action) => {
  switch (action.type) {
    case ADD_USER:
      return [...state, action.user]
    default:
      return state
  }
}

I added the ADD_USER bit to show why this format is valuable. It allows you to simply add in other actions, and have the state management update accordingly and automatically.

// store.js

import { combineReducers, createStore } from 'redux'
import users from './reducers/users.js'

export default createStore(
  combineReducers({ users }),
  {} // Initial State
)

Now, your store should work correctly with the binding that you have - and you're a bit more free to begin extending it with additional actions.

Troy Alford
  • 26,660
  • 10
  • 64
  • 82