Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialJonathan Grieve
Treehouse Moderator 91,253 Pointscannot read property map undefined
Hello all,
So there's another error with rendering the app but the Git Shell is compiling. The error in the console is
Uncaught TypeError: Cannot read property 'map' of undefined
at Scoreboard.render (bundle.js:33508)
at bundle.js:19806
at measureLifeCyclePerf (bundle.js:19086)
at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (bundle.js:19805)
at ReactCompositeComponentWrapper._renderValidatedComponent (bundle.js:19832)
at ReactCompositeComponentWrapper.performInitialMount (bundle.js:19372)
at ReactCompositeComponentWrapper.mountComponent (bundle.js:19268)
at Object.mountComponent (bundle.js:17591)
at ReactCompositeComponentWrapper.performInitialMount (bundle.js:19381)
at ReactCompositeComponentWrapper.mountComponent (bundle.js:19268)
Again, Would really appreciate a pointer or 2 on this if possible. Thanks :)
import React, {Component, PropTypes} from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as PlayerActionCreators from '../actions/player';
import AddPlayerForm from '../components/AddPlayerForm';
import Player from '../components/Player';
import Header from '../components/Header';
class Scoreboard extends Component {
static PropTypes = {
players: PropTypes.array.isRequired
};
render() {
const { dispatch, players } = this.props;
const addPlayer = bindActionCreators(PlayerActionCreators.addPlayer, dispatch);
const removePlayer = bindActionCreators(PlayerActionCreators.removePlayer, dispatch)
const updatePlayerScore = bindActionCreators(PlayerActionCreators.updatePlayerScore, dispatch) ;
const playerComponents = players.map((player, index) => (
<Player
index={index}
name={player.name}
score={player.score}
key={player.name}
updatePlayerScore={updatePlayerScore}
removePlayer={removePlayer}
/>
));
return (
<div className="scoreboard">
<Header players ={ players } />
<div className="players">
{ playerComponents }
</div>
<AddPlayerForm onAdd={addPlayer} />
</div>
);
}
}
const mapStateToProps = state => (
{
player: state
}
);
export default connect(mapStateToProps)(Scoreboard);
Updated Repo https://bitbucket.org/jg_digitalMedia/react-redux
5 Answers
Thomas Fogg
2,723 PointsI came across the same problem as you. The problem isn't in your scoreboard.js but your player.js reducer. This is how Guil has you write the file:
import * as PlayerActionTypes from '../actiontypes/player'
const initialState = {
players: [
{
name: 'Jim Hoskins',
score: 31,
},
{
name: 'Andrew Chalkley',
score: 20,
},
{
name: 'Alena Holligan',
score: 50,
},
]
}
export default function Player(state=initialState, action) {
switch(action.type) {
case PlayerActionTypes.ADD_PLAYER:
return [
...state,
{
name: action.name,
score: 0
}
]
case PlayerActionTypes.REMOVE_PLAYER:
return [
...state.slice(0, action.index),
...state.slice(action.index + 1)
]
case PlayerActionTypes.UPDATE_PLAYER_SCORE:
return state.map((player, index) => {
if(index === action.index) {
return {
...player,
score: player.score + action.score
}
}
return player
})
}
}
But this is how it actually needs to look:
import * as PlayerActionTypes from '../actiontypes/player';
const initialState = {
players: [{
name: 'Jim Hoskins',
score: 31,
},
{
name: 'Andrew Chalkley',
score: 20,
},
{
name: 'Alena Holligan',
score: 50,
}
]
}
export default function Player(state=initialState, action) {
switch(action.type){
case PlayerActionTypes.ADD_PLAYER: {
const addPlayerList = [...state.players, {
name: action.name,
score: 0
}];
return {
...state,
players: addPlayerList
};
}
case PlayerActionTypes.REMOVE_PLAYER: {
const removePlayerList = [
...state.players.slice(0, action.index),
...state.players.slice(action.index + 1)
];
return {
...state,
players: removePlayerList
};
}
case PlayerActionTypes.UPDATE_PLAYER_SCORE: {
const updatePlayerList = state.players.map((player, index) => {
if(index === action.index){
return {
...player,
score: player.score + action.score
};
}
return player;
});
return {
...state,
players: updatePlayerList
};
}
default:
return state;
}
}
The indentation is skewed here but notice the constants under each of the PlayerActionType blocks. Guil goes over this change later in the course but as far as I can tell the app won't function without the change. Hopefully this helps anyone else struggling with this problem in the future.
Guil Hernandez
Treehouse TeacherHey Jonathan Grieve,
In mapStateToProps
, player: state
should be players: state.players
. Hope this helps!
Jonathan Grieve
Treehouse Moderator 91,253 PointsHi Guil,
Thanks for this, I did make the change but sadly no effect
Michael Chi
8,330 PointsI had the exact same problem. The state was returned in the store but did not show up as props in the Scoreboard component. For me, the problem was with my action -> player.js.
Make sure all the methods in player js must match all the bindActionCreator methods. Hope this helps
Jonathan Grieve
Treehouse Moderator 91,253 PointsHi Michael, thanks for replying! This is still an open issue for me so I'll have a try with your advice and let you know how it goes! :-)
Jonathan Grieve
Treehouse Moderator 91,253 PointsThanks both for your tries. Sadly this bug isn't going to go away.
Chrome DevTools seems to think though that the problem is in line 23 of scoreboard.js
const playerComponents = player.map((player, index) => (
Micah Dunson
34,368 PointsI had a similar issue. Maybe check to make sure you are returning the player object in your reducer switch function. I didn't catch it at first in the video.
case PlayerActionTypes.UPDATE_PLAYER_SCORE: return state.map((player, index) => { if (index === action.index) { return { ...player, score: player.score + action.score }; } === return player; // I had previously forgot this line ======== });
gevuong
2,377 PointsIt looks like you're implementing destructuring assignment in this line of code:
const { dispatch, players } = this.props;
which states that you want to unpack a "players" property from an object defined in mapStateToProps. However, in mapStateToProps at the bottom of scoreboard.js, you set property to "player" and not "players". Therefore, the "players" prop is undefined, and invoking .map on "players" will return the error you have. That's my guess. Hope this helps.
For more info on destructuring assignment: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
Jonathan Grieve
Treehouse Moderator 91,253 PointsJonathan Grieve
Treehouse Moderator 91,253 PointsThanks for this, Thomas.
I had parked this project for all this time but I'd tried your edits and after a bit more debugging the project is now compiling!!!
As a result of your suggested edits I made a few more changes to the
playerComponents
map in scoreboard.jsAll sorted! :)