Home > database >  How to update state in an if statement contained in a map
How to update state in an if statement contained in a map

Time:02-23

I'm mapping an object and depending on the value of the currently mapped object (either 1 or greater than 1) it will go to it's respective If function.

I'm trying to update state to know how many object elements are matching the given requirements.

const displayMovements = () => {
  return(
    movements.map((m) => {
      if (m.value === 1) {
        setAmountEqualToOne(amountEqualToOne   1)
        return(
          <DisplayTemplateOne prop={m}/>
        )
      } else if (m.value > 1) {
        setAmountGreaterThanOne(amountGreaterThanOne   1)
          return(
            <DisplayTemplateTwo prop={m}/>
          )
      }
    })
  )
}

I'm running into an infinite loop error and am unsure of where to go next.

CodePudding user response:

Essentially the problem here is that you're updating state when rendering. And updating state triggers a re-render. So the cycle is:

  • Render the component
  • Which updates the state
  • Which re-renders the component
  • Which updates the state
  • and so on...

(As an aside, the state updates were broken too. State updates are asynchronous, so these were being queued up and ultimately only the last one will be made here. Don't update state in a loop, instead calculate the new state and update it once after the loop. But that's a separate issue.)

So, fundamentally, don't update state on every render. But then the question becomes, why are you trying to? What's the goal?

I'm trying to update state to know how many object elements are matching the given requirements.

Don't store that in state. That's a value that's calculated from state, not stored in state. And you can calculate that trivially when rendering the component. Something like this:

const amountEqualToOne = movements.filter(m => m.value === 1).length;
const amountGreaterThanOne = movements.filter(m => m.value > 1).length;

return(
  movements.map(m => 
    m.value === 1 ? <DisplayTemplateOne prop={m}/> :
    m.value > 1 ? <DisplayTemplateTwo prop={m}/> :
    null)
);

The above also corrects a potential issue where the callback passed to .map() wasn't always returning a value. In this case it will at least explicitly return null as a default case, instead of undefined.

But in this case wherever you intend to use amountEqualToOne and amountGreaterThanOne, they're re-calculated on every render and are available to be used.

Storing calculated values in state effectively means storing the same information twice in two different state values, and needing to manually keep those values synchronized. Which is a whole lot of trouble you don't really want.

  • Related