Home > front end >  Setting state variable in react loop with conditional logic
Setting state variable in react loop with conditional logic

Time:12-30

It appears that React does not like when you are setting the app state in a loop, so I was curious as to what the best approach for something like this was?

I have some logic that I am attempting to count the number of times the input variable is greater than the stat variable in my loop:

const [ statTotal, setStatTotal ] = useState(0);
{
    month.events.map((game) => {
        return (
            <tr key={ game.eventId }>
                <td>{ new Date(events[game.eventId].gameDate).toDateString() }</td>
                <td>{ events[game.eventId].atVs } { events[game.eventId].opponent.abbreviation }</td>
                <td>{ events[game.eventId].gameResult } { events[game.eventId].score }</td>
                {   
                    game.stats.map((stat, i) => {
                        
                        let className = '';

                        if (input > parseInt(stat)) {
                           className = 'red';
                           setStatTotal(statTotal   1);
                        } else {
                           className = 'green';
                        }

                        return (
                            <td key={ i } className={ className }>{ stat }</td>
                        );
                    })

                }
            </tr>
        );
    }) 
}

Is there a better way to do the logic and share the variable within the app state?

Edit I have cleaned up my original syntax and added a little more information for some additional clarity. My data is a little construed as it's broken down by months, then into a single game date, then each stat array for that game.

My input is a selected stat area and I am trying to capture the total number of times that particular stat is above the inputted stat number.

CodePudding user response:

Yes there is an amazing way to do that.

const totalStats = game.stats.filter(stat => stat < input).length;

return (
     <div>
    {
       game.stats.map((stat, i) => {
         if (stat < input ) {
             return <td key={ i } className={"red"}>{ stat }</td>;
         } else return <td key={ i } className={"green"}>{ stat }</td>;
    }
    </div>   
)

CodePudding user response:

statTotal looks to be a derived value, and it's not advised to use state for that.

Instead you can use just prepare some data for use in the render.

const totalStats = game.stats.filter(stat => input > stat).length

This filters the stats down to only the ones that pass your test and counts them. You can then use totalStats anywhere in your JSX to show that value.

If that list is very large and you want to improve performance, you could wrap that in a useMemo hook.

const totalStats =
  useMemo(() => game.stats.filter(stat => stat < input).length, [game.stats])

Now it will only recalculate the value when game.stats is changed.


Now when you render you can simplify this loop greatly since you don't have to do counting.

return <>
  {
    game.stats.map(stat => (
      <td key={i} className={input > stat ? 'red' : 'green'}>{ stat }</td>
    ))
  }
</>
  • Related