Reputation: 1093
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
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
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