Reputation: 7645
I have default state like this
this.state = {
selectedTab : 'tab1'
}
then
My render method like this
render(){
const { selectedTab } = this.state;
return(
<li>tab1</li><li>tab2</li>
<div id="content">
{selectedTab == 'tab1' ? this.renderTab1Content() : this.renderTab2Content()}
</div>
)
}
Everything worked above. But I failed to implement switch tab using click event.
I tried to bind onclick event on my li
to change the state of selectedTab, but I got infinity loop error. Like this
<li onClick={this.setState({selectedTab :'tab1'})}>Tab 1</li>
<li onClick={this.setState({selectedTab :'someothertab'})}>Tab 2/li>
Why?
Upvotes: 1
Views: 1942
Reputation: 1522
Whenever setState is called it causes render method to be run, and when u assign a function call instead of a function refrence to some variable, it calls it instantly.
In your case your function refrence, setState is called instantly on assignment and further setState calls render again, which further causes the setState call -> setState render, this creates an endless loop.
<li onClick={this.setState({selectedTab :'tab1'})}>Tab 1</li>
Render -> onclick => setState -> Render -> onclick => setState -> ....
To overcome this there are two ways,
You can use arrow functions, which also helps you to bind this reference of class to the function.
onClick={() => (this.setState())}
or if using simple function then you can bind them in the constructor.
constructor(props){
super(props);
this.onClickMethod = this.onClickMethod.bind(this);
// if this is not done then this in onclick method would not refer to the class
// instead it would that of assigned onClick callback as it is called
// by onclick Event handler hence exectuted in different context.
}
onClickMethod() {
this.setSate();
}
<li onClick={this.onClickMethod}>Tab 1</li>
Upvotes: 0
Reputation: 22872
I will introduce concept of "higher order functions here".
Basicaly, higher order function is function returning another function.
Let's modify onClick
handler and make it "higher order function".
// Original function
setActiveTab = (activeTab) => {
this.setState({ activeTab });
}
// Higher order function
setActiveTab = (activeTab) => {
// Here, we already "remember" name of tab which becomes active after click.
// Return "true" `onClick` handler from this place.
return () => {
// Finaly set state after click.
this.setState({ activeTab });
}
}
How will render function look like?
<li onClick={this.setActiveTab('tab1')}>Tab 1</li>
<li onClick={this.setActiveTab('someothertab')}>Tab 2/li>
Better, isn't it?
Upvotes: 1
Reputation: 282080
This error happens because you onClick
handler expects a function but you have called a statement to setState on the event and hence everytime you state changes using setState
, the render is called again and hence the onClick
again calls the setState
which triggers an infinite loop. You can do this by using an arrow function
in onClick
event or calling a separate function
<li onClick={() => this.setState({selectedTab :'tab1'})}>Tab 1</li>
or
handleClick = () =>{
this.setState({selectedTab :'tab1'})
}
<li onClick={this.handleClick}>Tab 1</li>
Upvotes: 2
Reputation: 9418
Every time your li
gets rendered, the setState is automatically called and hence you get into a loop. You should do something like this.
Create a method in the component like this
setActiveTab = (tab) => {
this.setState({selectedTab : tab});
}
Then in your render method rewrite your li
like this
<li onClick={() => this.setActiveTab('tab1')}>Tab 1</li>
<li onClick={() => this.setActiveTab('someothertab')}>Tab 2/li>
Upvotes: 0