idlehand
idlehand

Reputation: 421

React content data not correct until page refreshed

I have an app which displays athletes names and allows users to vote them up or down depending on their predicted upcoming performance.

I've started to implement code that checks the array of players and ranks all the players in the database based off the amount of votes they have, awarding those with ties the same ranks (If the top two people have 100 upvotes, they will both be ranked #1, etc,.)

The system seems to be working ok, however, sometimes it makes me refresh the page twice before the value next to the player is finally correct.

However, I'm mainly wondering if this is an acceptable way to do this sort of ranking — mainly, is it terribly inefficient being done in this way as a transaction in the render() return? I expect to have 100+ players in the database.

Is there another place in the code to do the ranking that would be more efficient?

Here's the code and some relevant variables:

let prevPlayerVotes = 0
let rankCount = 1

const orderedPlayersRank = _.orderBy(players, ['votes'], ['desc'])

<span className="trendHeaderUp">TRENDING UP</span>
{
    orderedPlayersRank.map((player) => {
        this.database.child(player.id).transaction(function(player) {
            if (player.votes >= prevPlayerVotes) {
                prevPlayerVotes = player.votes
                player.rank = rankCount
            } else if(player.votes < prevPlayerVotes) {
                rankCount++
                player.rank = rankCount
                prevPlayerVotes = player.votes
            } else {
                console.log("Rank calculation error.")
            }
            return player;
        })
    })
}
{
    orderedPlayersUp.map((player) => {
        return (
            <Player
                playerContent={player.playerContent}
                playerId={player.id}
                rank={player.rank}
                key={player.id}
                upvotePlayer={this.upvotePlayer}
                downvotePlayer={this.downvotePlayer}
                userLogIn={this.userLogIn}
                userLogOut={this.userLogOut}
                uid={this.uid}
            />
        )
    })
}
</div>
<div className="playersBody">
    <span className="trendHeaderDown">TRENDING DOWN</span>
    {
        orderedPlayersDown.map((player) => {
            return (
                <Player
                    playerContent={player.playerContent}
                    playerId={player.id}
                    rank={player.rank}
                    key={player.id}
                    upvotePlayer={this.upvotePlayer}
                    downvotePlayer={this.downvotePlayer}
                    userLogIn={this.userLogIn}
                    userLogOut={this.userLogOut}
                    uid={this.uid}
                />
            )
        })
    }
</div>

Thanks for the suggestions.

Reference image:

ref

Upvotes: 2

Views: 227

Answers (2)

Seth McClaine
Seth McClaine

Reputation: 10040

Another thing to call out, with es6 pointer function, you don't need to specify return if you aren't doing any other data manipultion

So instead of

const alwaysTrue = () => { return true };

You can do

const alwaysTrue = () => true;

Example with your code:

  orderedPlayersDown.map((player) => (
        <Player
            playerContent={player.playerContent}
            playerId={player.id}
            rank={player.rank}
            key={player.id}
            upvotePlayer={this.upvotePlayer}
            downvotePlayer={this.downvotePlayer}
            userLogIn={this.userLogIn}
            userLogOut={this.userLogOut}
            uid={this.uid}
        />
    ))

Upvotes: 1

Seth McClaine
Seth McClaine

Reputation: 10040

You do not want to do the ranking in the render. This would be inefficient.

Any time anything changes (a click of an up/down vote for instance, or if you have a text field and someone types a character) the render is fired and most likely every user action does not result in the need to rerank the list.

If the list only needs to be ranked once, do it in the constructor.

If the list needs to be ranked every time a vote is made, do it in the constructor and the function that handles when the vote button is clicked.

  • You would only want to rank the trending up if the up is clicked, and only want to rank the trending down if the down is clicked

Upvotes: 2

Related Questions