ononononon
ononononon

Reputation: 1093

React - toggle css class

i want to be able to toggle class "active" on/off on a single item of a list. Say we have a list of elements:

<ul>
  <li><a href="#" className="list-item">First</a></li>
  <li><a href="#" className="list-item">Second</a></li>
  <li><a href="#" className="list-item">Third</a></li>
</ul>

and I want to be able to add class "active" on a second element on click. I cannot use state for that, because it would change the classes of other 2 elements, if we add the condition there, right ?

So the solution could be to create a sub-component say <ListItem /> that could have its own state and own onclick method, that would change only his own class. But then, when we want to remove class "active" on other elements on click, this sub-component would have to dispatch method to a parent to remove class from other elements. It seems pretty complicated for a task of a easy kind ( you know the 10secs-in-jquery kind).

Does anyone have an easier solution for this ?

It would be very nice to not have to use another big npm module for this, document.getElementsByClassName (obviously) nor refs.

Upvotes: 0

Views: 964

Answers (2)

Sagiv b.g
Sagiv b.g

Reputation: 31024

you can manage the selected state outside the item component and pass it as a prop.
An event handler of onSelect / onClick can trigger and change the state.

const data = [1,2,3,4,5];

class List extends React.Component {
	constructor(props){
			super(props);
      
      this.state = {
      	selectedItem: 0
      };
      this.onSelect = this.onSelect.bind(this);
  }
  
  onSelect(id){
  	this.setState({
    	selectedItem: id
    });
  }
  
  render() {
  	const {selectedItem} = this.state;
  	return ( 
      <ul>
          {data.map((d, index) => {
          	return <ListItem 
                      key={index}
                      selected={index + 1  == selectedItem}
                      value={d}
                      id={d}
                      onSelect={this.onSelect}
                    />
          })}
          
      </ul>
    )
  }
}

const ListItem = (props) => {

  const onSelect = (e) => {
  	props.onSelect(e.target.id);
  }
  
  const className = props.selected && "selected";
  	
	return <li className={className} id={props.id} onClick={onSelect}>{props.value}</li>
}

ReactDOM.render(<List />, document.getElementById("root"));
ul{
  list-style: none;
}

li{
    padding: 5px;
    border: 1px solid #ccc;
    cursor: pointer;
}

li.selected{
  background-color: green;
  color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Upvotes: 2

Kevin Pei
Kevin Pei

Reputation: 5872

The correct way to approach this problem would be to have a state variable that defines which one is currently "active", i.e.

this.state = {
    active: "first" // (or "second", "third", null, etc..) 
};

Then, you can use an inline if statement like so:

<li><a href="#" className={"list-item" + (this.state.active == "first" ? " active": "")}>First</a></li>

Note that I am assuming you want to hardcode these list elements - if these elements are dynamically generated it's a simple matter of setting this.state.active to being the index/ref of the currently selected element.

Upvotes: 2

Related Questions