I'm struggling with implementing 'toggle class' functionality in React.
I have the NavSidebar component which is an unordered list ul. My NavListItem component is list item li.
When the list item is clicked I need to give the class name active to the clicked li and other list elements should get an empty class name.
Here's what I've come up with by far:
class NavListItem extends React.Component {
constructor(props) {
super(props);
this.state = { active: false };
}
setActive(bool) {
this.setState({ active: bool });
}
render() {
let index = this.props.key;
let item = this.props.item;
return (
<li className={this.state.active ? 'active' : ''}
onClick={this.setActive(this.props.setActive).bind(this)} >
<a href={'#'+item}>{item}</a>
</li>
);
}
}
class NavSidebar extends React.Component {
constructor(props) {
super(props);
}
render () {
let items = this.props.navItems.map( (item, index) => {
return (
<NavListItem key={index} item={item} setActive={true} />
);
});
return (
<div className="col-sm-2">
<nav className="nav-sidebar">
<ul className="nav">
{items}
<li className="nav-divider" />
<li>
<a href="#"><i className="glyphicon glyphicon-home"></i> Back Home</a>
</li>
</ul>
</nav>
</div>
);
}
}
NavSidebar.propTypes = {
navItems: React.PropTypes.array
};
Unfortunately, this doesn't work, it never even touches the className of the elements and I can't come up with the working solution.
Could you please help me with that?
There is no error message here?
onClick={this.setActive(this.props.setActive).bind(this)}
Because you are binding undefined, result of calling this.setActive(this.props.setActive)
and even if you remove the bind, it will not work as the click handler will be undefined. Also, the state should never be modified inside render.
In any case, because you want to update more than one item (the new selected one and the old one), the parent should be responsible of this and should:
Something like this (not tested):
class NavListItem extends React.Component {
constructor(props) {
super(props);
}
setActive(bool) {
this.props.onItemActive(this.props.item);
}
render() {
let item = this.props.item;
return (
<li className={this.props.active ? 'active' : ''}
onClick={this.setActive.bind(this)} >
<a href={'#'+item}>{item}</a>
</li>
);
}
}
class NavSidebar extends React.Component {
constructor(props) {
super(props);
this.state = {activeItem: null};
}
onItemActive(item) {
this.setState({activeItem: item};
}
render () {
let self = this;
let items = this.props.navItems.map( (item, index) => {
return (
<NavListItem key={index} item={item}
onItemActive={self.onItemActive.bind(self)}
active={item === self.state.activeItem} />
);
});
return (
<div className="col-sm-2">
<nav className="nav-sidebar">
<ul className="nav">
{items}
<li className="nav-divider" />
<li>
<a href="#"><i className="glyphicon glyphicon-home"></i> Back Home</a>
</li>
</ul>
</nav>
</div>
);
}
}
NavSidebar.propTypes = {
navItems: React.PropTypes.array
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With