Reputation: 640
I have a <Sidebar />
component which creates two <TabLabel />
components.
I want to toggle the className is-active
, if you click a tab label the class is-active
should be added to the <li>
element and removed on the other one.
There is no error ocuring, but the function toggleClass()
doesn't seem to get invoked.
<Sidebar />
Component:
constructor() {
super();
this.state = {
active: 'generator'
}
this.toggleClass = this.toggleClass.bind(this);
}
toggleClass() {
this.setState({active: 'code'});
}
render() {
return (
<div className="sidebar">
<ul className="tabs-list">
<TabLabel onClick={() => this.toggleClass()} active={this.state.active} text="Generator" />
<TabLabel onClick={() => this.toggleClass()} active={this.state.active} text="Code" />
</ul>
</div>
);
}
<TabLabel />
Component:
render() {
return(
<li className={this.props.text.toLowerCase() === this.props.active ? "is-active" : null}>
<h2>{this.props.text}</h2>
</li>
);
}
Upvotes: 2
Views: 8735
Reputation: 7424
Why don't you keep TabLabel
as dumb as possible and only propagate props to it?
Also, TabLabel
needs to dispatch click changes so Sidebar
knows which Tab has been selected.
Testability gets easier and you can even improve TabLabel
rendering on Sidebar
(such as using an array of tabs).
class Sidebar extends React.Component {
constructor() {
super()
this.state = {
active: 'generator',
}
}
toggleClass(tab) {
this.setState({
active: tab,
})
}
render() {
const { active } = this.state
return (
<div>
<div className="sidebar">
<ul className="tabs-list">
<TabLabel
onClick={this.toggleClass.bind(this, 'generator')}
active={active === 'generator'}
text="Generator"
/>
<TabLabel
onClick={this.toggleClass.bind(this, 'code')}
active={active === 'code'}
text="Code"
/>
</ul>
</div>
</div>
)
}
}
const TabLabel = ({ active, text, onClick }) =>
<li onClick={onClick} className={active ? 'is-active' : null}>
<h2>{text}</h2>
</li>
ReactDOM.render(
<Sidebar />,
document.getElementById('root')
)
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
li.is-active {
background-color: red;
color: white;
}
<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: 1
Reputation: 193271
The onclick
event will not propagate from inside TabLabel
to the onClick
handler. You need to set dedicated event prop and invoke it in the TabLabel
component:
render() {
const isActive = this.props.text.toLowerCase() === this.props.active.toLowerCase()
return(
<li onClick={() => this.props.onSelect(this.props.text)} className={isActive ? "is-active" : null}>
<h2>{this.props.text}</h2>
</li>
);
}
And in Sidebar:
toggleClass(active) {
this.setState({active});
}
render() {
return (
<div className="sidebar">
<ul className="tabs-list">
<TabLabel onSelect={this.toggleClass} active={this.state.active} text="Generator" />
<TabLabel onSelect={this.toggleClass} active={this.state.active} text="Code" />
</ul>
</div>
);
}
Upvotes: 1