Reputation: 3535
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?
Upvotes: 3
Views: 5541
Reputation: 47978
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
};
Upvotes: 5