How to dynamically add and remove class on click with React?

Ronald Langeveld picture Ronald Langeveld · Feb 25, 2019 · Viewed 13.9k times · Source

I have a list of links.

I'm adding a class on click, called "is-active". At the same time, I would like to remove all the existing "is-active"s except for on the link I clicked on. There may only be one element with the class "is-active" as that will 'live' page. (Using bulma css)

Here's the code I've tried so far. It's adding classes but not removing them.

class Menu extends Component {

    constructor(props) {
        super(props);
        this.state = {addClass: false}
    };

    handleClick(e) {
        if(e.target.class === 'is-active'){
            e.target.className = '';
            console.log('remove')
        }else{
            e.target.className = 'is-active';
            console.log('add class')
        }
    }  

    render() {
        <ul className="menu-list">
            { this.props.getList.map(list =>
                <Link onClick={this.handleClick.bind(this)} key={list.id} to="">{list.title}</Link>                    
            )}
        </ul>
    }

}

export default SideMenu;

Advice would be sooo much appreciated.

Answer

0xc14m1z picture 0xc14m1z · Feb 25, 2019

You must avoid touching the DOM by yourself, let's React do it for you.

You want to keep a signal in the state that tell's you whether an element in the list is active or not, and use that signal to set a class or not in your rendering phase:

state = {
  activeId: null  // nothing selected by default, but this is up to you...
}

handleClick(event, id) {
  this.setState({ activeId: id })
}

render() {
  <ul className="menu-list">
  {
    this.props.getList.map(list =>
      <Link key={ list.id }
            className={ this.state.activeId === list.id && 'is-active' }
            onClick={ this.handleClick.bind(this, list.id) } 
            to="">
        { list.title }
      </Link>                    
    )
  }
  </ul>
}

This way, at each render, the id of each item in your getList prop is compared to the one you keep in your state, then:

  1. if it's the active id, it assign the 'is-active' class;
  2. if it's not the active one, it clears the previous className (in case it was 'is-active';

Hope it helps :)