Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

React: how to toggle css class in a component based on 3 different state elements

I have a Card component that has 4 potential states: "active", "selected", "discarded", "complete". Depending on the state, I need to display a different css class.

The states are set by clicking on specific parts of the card and each part is a "toggle" (one click sets it, another click "unsets" it):

  • default state is active,
  • if the user click on the card, it gets selected (the css class I need to add is "overlay-selected")
  • if the user click on "discard" btn inside the card it sets to "discarded" (the css class I need to add is "overlay-discarded" )
  • if the user click on "complete" btn inside the card it sets to "complete" (the css class I need to add is "overlay-complete" )

The state is stored at the "App" level and I am passing it to the component through props. This means that for updating the states I am passing some "handler" from the app to the component (SelectCard, DiscardCard)

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Here below is my code.

I think they way I am approaching the problem is not ideal because I am having problem on how to best defyining the ClassName of the variable.

I initially thought about using a ternary if statement, but with more than one status it doesn’t work. Especially because I need to take care of the "toggle" use-case.

App


function App() {
  const [people, setPeople] = useState(data['people'].map(
    el=>{
      return {
        ...el,
        'key' : nanoid(),
      }
    }
  ))

 

  function SelectCard(CardKey){
    setPeople(oldPeople=>{
      return oldPeople.map(el=>{

        return el.key === CardKey
                ? { ...el, 'selected':!el.selected}
                : { ...el, 'selected':false}
          })
    })
  }

  function DiscardCard(CardKey){
    setPeople(oldPeople=>{
      return oldPeople.map(el=>{

        return el.key === CardKey
                ? { ...el, 'active':!el.active}
                : { ...el}
          })
    })
  }

  const cards = people.map(el=>{
    return <Card 
            key = {el.key} 
            item={el} 
            onPress={()=>SelectCard(el.key)}
            onDiscard={()=>DiscardCard(el.key)}
          />
  })

  
  return (
    <div className="App">
      <div className='container'>
        <div className='left'>
          <div className='cards'>
            {cards}
          </div>
        </div>
        <div className = 'right'>
          ....
        </div>
     </div>
     
    </div>
  )
}

export default App


Card

function Card(props) {


  const className = `card ${props.item.selected ? "overlay-selected" : ""}`

  return (
    <div 
        className={className} 
        onClick={(event)=>{props.onPress()}}>

        <img className='card-img' alt='Card Image' src={props.item.img} />
        <h3 className='card-title'>{props.item.name} </h3>
        
        { props.item.selected ? 
        
            <div className='card-cta'>
                <button 
                    className='btn btn-back'
                    onClick={ props.item.selected ?  (event)=>
                        { 
                            event.preventDefault()
                            props.onPress
                        }
                         : ()=>{}}
                >Back</button>
                <button 
                    className='btn btn-discard'
                    onClick={ props.item.selected ?  (event) =>{
                            event.preventDefault()
                            props.onDiscard 
                        } 
                        :
                        ()=>{}}
                >Discard</button>
            </div>
        : 
        <p className='card-description'>{props.item.description} </p>  
    
        }
        
    </div>
  )
}


>Solution :

Achieving this can be creating a function that maps the state of your card to the appropriate class name. This function can be called from within the Card component and would return the class name as a string.

function getClassName(state) {
  switch (state) {
    case "active":
      return "";
    case "selected":
      return "overlay-selected";
    case "discarded":
      return "overlay-discarded";
    case "complete":
      return "overlay-complete";
    default:
      return "";
  }
}

Then, in your Card component, you can call this function to get the appropriate class name based on the state of the card.

function Card(props) {
  const className = `card ${getClassName(props.item.state)}`;

  return (
    // ...
  )
}

So you can easily update the class name of your card based on its state by simply calling getClassName and passing in the current state of the card.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading