Unable to update during an existing state transition error in React

Inside my rendering of return (), I have:

<button onClick={ this.selectTimeframe('Today') } className={ this.setActiveIf('Today') } type="button">Today</button> 

What is this function:

 selectTimeframe(timeframe) { // this.setState({ timeframe }); } 

^ I have to comment on setState, otherwise I will get this error, which I posted above, and the application crashes.

I have this in my constructor:

this.selectTimeframe = this.selectTimeframe.bind(this);

I found this answer here , but it does not make sense, how can I pass a variable? Or does he say that each unique button needs a unique function? How to avoid calling it inside the render?

Full code

 import React from 'react'; export class TimeframeFilter extends React.Component { constructor(props) { super(props); this.state = { timeframe: 'Today' }; this.selectTimeframe = this.selectTimeframe.bind(this); this.setActiveIf = this.setActiveIf.bind(this); } componentDidMount() { console.log('%c TimeframeFilter componentDidMount', 'background: #393939; color: #bada55', this.state); } selectTimeframe(timeframe) { // this.setState({ timeframe }); } setActiveIf(timeframe) { return this.state.timeframe === timeframe ? 'btn btn-default active' : 'btn btn-default'; } render() { return ( <div className="fl"> <span className="label label-default mr10">Timeframe</span> <div className="btn-group btn-group-sm mr20" role="group"> <button onClick={ this.selectTimeframe('Today') } className={ this.setActiveIf('Today') } type="button">Today</button> <button onClick={ this.selectTimeframe('Week') } className={ this.setActiveIf('Week') } type="button">Week</button> <button onClick={ this.selectTimeframe('Month') } className={ this.setActiveIf('Month') } type="button">Month</button> <button onClick={ this.selectTimeframe('Year') } className={ this.setActiveIf('Year') } type="button">Year</button> <button onClick={ this.selectTimeframe('All') } className={ this.setActiveIf('All') } type="button">All</button> </div> </div> ); } } export default TimeframeFilter; 
+5
source share
2 answers

You must pass the value of the onClick function using the arrow function or bind method , otherwise it will simply return the value to onClick every time a rerender occurs, and if you use setState in it, it will call rerender and funciton to call again and thus repetition of the process.

Do it like

 <button onClick={ ()=> this.selectTimeframe('Today') } className={ this.setActiveIf('Today') } type="button">Today</button> 

or

 <button onClick={ this.selectTimeframe.bind(this, 'Today') } className={ this.setActiveIf('Today') } type="button">Today</button> 

Hope I could explain it clearly to you. :)

EDIT:. Although the above approach solves the problem, it is not an optimal approach due to performance reasons. We should avoid binding methods inside the renderer because during re-rendering it will create new methods instead of the old one, which will affect performance.

See this answer on Avoiding Binding Inside a Rendering Method

+2
source

You are currently calling this.selectTimeframe('Today') in your render method. You probably want

onClick={() => this.selectTimeframe('Today') }

or a little smarter way

 <button onClick={ this.selectTimeframe.bind(this, 'Today') } className={ this.setActiveIf('Today') } type="button">Today</button> selectTimeframe.bind(key) { switch(key){ case 'Today': //your logic break; } } 
+1
source

All Articles