Render components with different style based on a boolean state

Viewed 33

I'm writing this simple web application for displaying employees. To display each employee, I use a Card component, that gets rendered inside a CardGrid component, based on the number of employees there is.

What I'm trying to do is render each card with a different background value for visual clarity. I try to store a boolean state inside the CardGrid, that gets toggled by setState setter method, that gets passed into each card and called on the render of each individual component.

My issue is, that instead of the Cards having each different color, their color is the same, but it keeps flicking between the two values really fast (epilepsy warning lol).

Does anyone know what I'm missing? Why is the state shared among all of the Card instances?

//CardGrid.js
export default function CardGrid(props){
  const {data} = props;
  const [colorSwitch, setColorSwitch] = useState(true)
  

  return(
    <div className="card-grid">
      {data.map((d)=>
        <Card
        name={d.name}
        lastName={d.lastName}
        present={d.present}
        time={d.time}
        colorSwitch={colorSwitch}
        setColorSwitch={setColorSwitch}
        />
      )}
    </div>
  )
}
//Card.js
export default function Card(props){
  const {name, lastName, present, time, colorSwitch, setColorSwitch} = props
  
  useEffect(()=>{
    setColorSwitch(!colorSwitch)
  })
  return (
    <div
    className="card"
    style={present?(colorSwitch? {backgroundColor: "green"}:{backgroundColor: "red"}):{backgroundColor: "grey"}}>
      <p className="card-text">{name} {lastName}</p>
    </div>
  )
}
1 Answers

The useEffect hook is missing a dependency array and unconditionally enqueues a React state update. This means all cards use the same state value and render loop (i.e. the "flashing"). It seems you just want to alternate a color/style when rendering. Use the mapped array index and alternate on evens/odds.

Example:

export default function CardGrid({ data }) {
  return(
    <div className="card-grid">
      {data.map((d, index)=>
        <Card
          name={d.name}
          lastName={d.lastName}
          present={d.present}
          time={d.time}
          backgroundColor={index % 2 ? "red" : "green"} // evens = red, odds = gree
        />
      )}
    </div>
  )
}

...

export default function Card({ name, lastName, present, time, backgroundColor }) {
  return (
    <div
      className="card"
      style={{ backgroundColor: present ? backgroundColor : "grey" }}
    >
      <p className="card-text">{name} {lastName}</p>
    </div>
  )
}
Related