I am trying to create a sidemenu which has collapsible options.
Below is my code:
export default class CRSideMenu extends React.Component {
constructor(props) {
super(props);
this.state = {
fprActive: true
};
autoBind(this);
}
toggleFPR() {
console.log('Setting fprActive from ', this.state.fprActive, ' to ', !this.state.fprActive);
this.setState({
fprActive: !this.state.fprActive
});
}
render() {
console.log('render', this.state.fprActive);
return (
<ul className='list-group list-group-nav'>
<li>
<a
href='#'
className={classnames('list-group-item', this.state.fprActive && 'active', 'has-subnav')}
onClick={this.toggleFPR} >
FPR
</a>
<ul className='list-group list-group-nav'>
<li>
<a href='' className='list-group-item'>FR</a>
</li>
</ul>
</li>
</ul>
);
}
}
When I printed out the this.state.fprActive
in the render() method, I see the following:
How come my fprActive is being automatically setback to 'true' when I click only once?
I can't replicate the problem at this end, but the symptom says that your page is being refreshed when you click the anchor because you're not preventing the default action. Have toggleFPR
call preventDefault
on the event object it receives:
toggleFPR(event) {
// ^^^^^ ------------ ***
event.preventDefault(); // ***
console.log('Setting fprActive from ', this.state.fprActive, ' to ', !this.state.fprActive);
this.setState({
fprActive: !this.state.fprActive
});
}
Separately: You're breaking one of the fundamental React rules here:
console.log('Setting fprActive from ', this.state.fprActive, ' to ', !this.state.fprActive);
this.setState({
fprActive: !this.state.fprActive
});
When setting state based on existing state, you must use the callback version, not the version you pass an object into:
this.setState(({fprActive}) => {
console.log('Setting fprActive from ', fprActive, ' to ', !fprActive);
return {fprActive: !fprActive};
});
If you don't, it'll work most of the time, and fail in hard-to-diagnose ways sometimes.