Skip to content
Advertisement

On button click, how to add selected class and remove from all other buttons in React functional component?

I am currently learning React and I have a functional component for a menu. When a value is clicked I want to add the ‘choice-selected’ class to visually show it has been selected and make sure no other button has the class. Is there a way to create this behavior without creating a separate useState hook for every selection?

Here is my code:

function SortMenu(props){
    const [clickedDay, setClickedDay] = useState('');
    const [clickedMonth, setClickedMonth] = useState('');
    const [clickedYear, setClickedYear] = useState('');
    const choice = (value) =>{
        props.setSort(value);

        switch(value){
            case 'day':
                setClickedDay( (prevVal) => {
                    prevVal =='' ? setClickedDay('choice-selected'): setClickedDay('');
                    setClickedMonth('');
                    setClickedYear('');
                });
                break;
            case 'month':
                setClickedMonth( (prevVal) => {
                    prevVal =='' ? setClickedMonth('choice-selected'): setClickedMonth('');
                    setClickedDay('');
                    setClickedYear('');
                })
                break;
            case 'year':
                setClickedYear( (prevVal) => {
                    prevVal =='' ? setClickedYear('choice-selected'): setClickedYear('');
                    setClickedDay('');
                    setClickedMonth('');
                })
                break;

        }
    }
    return(
    <nav className="sortmenu">
        <div className={`${clickedDay} choice`} onClick={() => {choice("day");}}>Day</div>
        <div className={`${clickedMonth} choice`} onClick={() => {choice("month")}}>Month</div>
        <div className={`${clickedYear} choice`} onClick={() => {choice("year")}}>Year</div>
    </nav>
    )
}

Currently my code does work, but if I need to add more choices I have to not only add another case, but add the new choices in the existing cases as well. I am wondering if there is an easier or better way to implement this behavior?

Advertisement

Answer

Here is a working example of the solution I described in the comments.

const { useState } = React;

const SortMenu = () => {
  const [clickedChoice, setClickedChoice] = useState('');

  const choice = (value) => {
      setClickedChoice(prev => prev === value ? '' : value);
  };

  return (
    <nav>
      <div
        className={`${clickedChoice === 'day' ? 'choice-selected' : ''} choice`}
        onClick={() => choice('day')}
      >Day</div>
      <div
        className={`${clickedChoice === 'month' ? 'choice-selected' : ''} choice`}
        onClick={() => choice('month')}
      >Month</div>
      <div
        className={`${clickedChoice === 'year' ? 'choice-selected' : ''} choice`}
        onClick={() => choice('year')}
      >Year</div>
    </nav>
  )
}

ReactDOM.render(<SortMenu/>, document.querySelector('#root'));
.choice {
  border: 1px solid black;
  padding: 2px;
}

.choice-selected {
  background-color: pink;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
Click an option to de/select it.
<div id="root"></div>
User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement