Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

JavaScript React Basics (retired) Designing Data Flow Building the Statistics Component

totalPoints doesn't update when the user increases or decreases the counter for a player

Hi,

I am running this locally using React App, so slightly different to the way the video does it, but everything has worked so far for me, a be it with a little googling and figuring out for myself.

However i am stuck with this, my code looks the same as on screen and in the download files, but the totalPoints doesn't update.

totalPoints = this.props.players.reduce(function (total, player) {

        return total + player.score;

    }, 0);

The totalPoints correctly displays, but doesn't get updated when the user changes the score using the + or - buttons

Update:

This is also the same for adding and removing users, in the next video. The users are added and removed fine, but the playters stat is not updated.

5 Answers

Mike Jensen
Mike Jensen
11,718 Points

Can you post your code for how you update the state when a player's individual score changes? If the total points shown is initially correct, and a player's individual score also seems to update in response to the +/- buttons being clicked, you may not be updating your state correctly.

Here is my example (also using a local create-react-app, with components in separate files):

  onScoreChange(index, delta) {
    const player = [...this.state.players][index]

    player.score += delta
    this.setState(player)
  }

Hi There,

Thanks for responding.

My code is this:

onScoreChange = (index, delta) => {

        this.setState(prevState => {

            return {

                score: prevState.players[index].score += delta

            };

        });

    };

I have tried you code snippet and this didn't work for me either. But my understanding is lacking it seems, having now looked back at this, so think i will run through this bit of the course again anyway.

Mike Jensen
Mike Jensen
11,718 Points

Where are you defining onScoreChange?

This should be defined in the nearest common ancestor of the components which are passed player information.

onScoreChange should then be passed in to a property as a callback from the ancestor component, all the way through the the counter component where the click event happens.

In my app this looks a little like this:

//App.js
...

onScoreChange() {
... code here
}

render() {
...
<Player
 onScoreChange={(delta) => this.onScoreChange(index, delta)}
 ...
/>
}

//Player.js
...

render() {
 ...

 <Counter
  score={this.props.score}
 onChange={this.props.onScoreChange}
/>
}

// Counter.js
...

render() {
...

<button className="counter-action decrement" onClick={() => this.props.onChange(-1)}> - </button>
}

Here is the reference article which describes how state should be lifted up to the nearest common ancestor, and the use of callbacks to pass requests for mutation back up through the component cascade:

https://reactjs.org/docs/lifting-state-up.html

Hi Again,

I have managed to fix this issue, but to be honest i don't know why it works and the original way didn't. I suspect its something to do with 'this' and scope, but not sure.

The fix was to take the values from TotalPlayers and TotalPoints and put them directly into the <td>, rather than calling them in the <td>

Original:

<tbody>

                    <tr>

                        <td>Players:</td>
                        <td>{this.totalPlayers}</td>

                    </tr>

                    <tr>

                        <td>Total Points:</td>
                        <td>{this.totalPoints}</td>

                    </tr>

                </tbody>

Fix:

<tbody>

                    <tr>

                        <td>Players:</td>
                        <td>{this.props.players.length}</td>

                    </tr>

                    <tr>

                        <td>Total Points:</td>
                        <td>{this.props.players.reduce(function (total, player) {

                            return total + player.score;

                        }, 0)}</td>

                    </tr>

                </tbody>
Mike Jensen
Mike Jensen
11,718 Points

Hi Duncan,

Could you post your full original code for your Stats component?

Here is mine for example:

import React, { Component } from 'react'
import PropTypes from 'prop-types'

export default class Stats extends Component {
  render() {
    const totalPlayers = this.props.players.length
    const totalPoints = this.props.players.reduce((accumulator, player) => accumulator + player.score, 0)

    return (
      <table className="stats">
        <thead></thead>
        <tbody>
          <tr>
              <td>Players:</td>
              <td>{totalPlayers}</td>
          </tr>
          <tr>
            <td>Total points:</td>
            <td>{totalPoints}</td>
          </tr>
        </tbody>
      </table>
    )
  }
}

Stats.propTypes = {
  players: PropTypes.array.isRequired
}

Hi Mike,

I have worked out where i have gone wrong from your code example. I had my totalPlayers and totalPoints variables in the wrong place in my code.

This all now works fine.

Thank you very much for all your help.