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 trialA R
12,834 PointsRunning into issue with 'this' and react
I'm not sure exactly what's up, it seems like there's an issue passing the props between the AddPlayerForm and the App, but I'm not sure what I'm doing wrong. I get errors like this:
TypeError: this.state is undefined
handleAddPlayer
src/components/App.js:66
63 |
64 | handleAddPlayer(name){
65 | this.setState({
> 66 | players:[
67 | //brings in old array of players and tacks on news ones.
68 | ...this.state.players,
69 | { name,
AddPlayerForm/_this.handleSubmit
src/components/AddPlayerForm.js:17
14 | //prevents form from submitting
15 | e.preventDefault();
16 | //adds player using the form's value as information
> 17 | this.props.addPlayer(this.state.value);
18 | this.setState({ value: '' });
19 | }
20 |
for reference, here is my code. APP.JS
//named import lets you create Class without extending React.Component
//Class app extends Component, not React.Component
import React, { Component } from 'react';
import Header from './Header';
import Player from './Player';
import AddPlayerForm from './AddPlayerForm';
class App extends Component {
state = {
players: [
{
name: "Guil",
score: 0,
id: 1
},
{
name: "Treasure",
score: 0,
id: 2
},
{
name: "Ashley",
score: 0,
id: 3
},
{
name: "James",
score: 0,
id: 4
}
]
};
//player id counter
prevPlayerId = 4;
handleScoreChange = (index, delta) => {
this.setState( prevState => {
// New 'players' array – a copy of the previous `players` state
const updatedPlayers = [ ...prevState.players ];
// A copy of the player object we're targeting
const updatedPlayer = { ...updatedPlayers[index] };
// Update the target player's score
updatedPlayer.score += delta;
// Update the 'players' array with the target player's latest score
updatedPlayers[index] = updatedPlayer;
// Update the `players` state without mutating the original state
return {
players: updatedPlayers
};
});
}
handleRemovePlayer = (id) => {
this.setState( prevState => {
return {
players: prevState.players.filter(p => p.id !== id)
};
});
}
handleAddPlayer(name){
this.setState({
players:[
//brings in old array of players and tacks on news ones.
...this.state.players,
{ name,
score: 0,
//increments id by one each time
id: this.prevPlayerId +=1,
}
]
})
}
render() {
return (
<div className="scoreboard">
<Header
title="Scoreboard"
players={this.state.players}
/>
{/* Players list */}
{this.state.players.map( (player, index) =>
<Player
name={player.name}
score={player.score}
id={player.id}
index={index}
key={player.id.toString()}
changeScore={this.handleScoreChange}
removePlayer={this.handleRemovePlayer}
/>
)}
<AddPlayerForm addPlayer={this.handleAddPlayer}/>
</div>
);
}
}
export default App;
and AddPlayerForm
import React, { Component } from 'react';
class AddPlayerForm extends Component {
state = {
value:''
};
//adds the form value to this components' state
handleValueChange = (e) => {
this.setState({ value: e.target.value });
}
handleSubmit = (e)=>{
//prevents form from submitting
e.preventDefault();
//adds player using the form's value as information
this.props.addPlayer(this.state.value);
this.setState({ value: '' });
}
render(){
return(
//uses React's onSubmit property with a function the user writes
<form onSubmit={this.handleSubmit}>
<input
type="text"
value={this.state.value}
onChange={this.handleValueChange}
placeholder="Enter a player's name"
/>
<input
type="submit"
value="Add Player"
/>
</form>
)
}
}
export default AddPlayerForm;
3 Answers
Steven Parker
231,269 PointsI see you have arrow functions in this code, and one of the ways they are different from conventional functions is that they don't establish a "this" value.
For more details about it, and about the other differences, see the MDN page on Arrow function expressions.
A R
12,834 PointsThanks, I'll give it a try!
A R
12,834 PointsI changed the handleAddPlayer to an arrow function and the rest to normal functions. I guess the 'this' in the handleAddPlayer was getting passed on instead of being used to establish a players array and that was causing the problem...
handleAddPlayer = (name) => {
this.setState({
players: [
...this.state.players,
{
name,
score: 0,
id: this.prevPlayerId += 1
}
]
})
}