[reactjs] ReactJS: Warning: setState(...): Cannot update during an existing state transition

I am trying to refactor the following code from my render view:

<Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChange.bind(this,false)} >Retour</Button>

to a version where the bind is within the constructor. The reason for that is that bind in the render view will give me performance issues, especially on low end mobile phones.

I have created the following code, but I am constantly getting the following errors (lots of them). It looks like the app gets in a loop:

Warning: setState(...): Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`.

Below is the code I use:

var React = require('react');
var ButtonGroup = require('react-bootstrap/lib/ButtonGroup');
var Button = require('react-bootstrap/lib/Button');
var Form = require('react-bootstrap/lib/Form');
var FormGroup = require('react-bootstrap/lib/FormGroup');
var Well = require('react-bootstrap/lib/Well');

export default class Search extends React.Component {

    constructor() {
        super();

        this.state = {
            singleJourney: false
        };

        this.handleButtonChange = this.handleButtonChange.bind(this);
    }

    handleButtonChange(value) {
        this.setState({
            singleJourney: value
        });
    }

    render() {

        return (
            <Form>

                <Well style={wellStyle}>

                    <FormGroup className="text-center">

                        <ButtonGroup>
                            <Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChange(false)} >Retour</Button>
                            <Button href="#" active={this.state.singleJourney} onClick={this.handleButtonChange(true)} >Single Journey</Button>
                        </ButtonGroup>
                    </FormGroup>

                </Well>

            </Form>
        );
    }
}

module.exports = Search;

This question is related to reactjs constructor setstate

The answer is


Looks like you're accidentally calling the handleButtonChange method in your render method, you probably want to do onClick={() => this.handleButtonChange(false)} instead.

If you don't want to create a lambda in the onClick handler, I think you'll need to have two bound methods, one for each parameter.

In the constructor:

this.handleButtonChangeRetour = this.handleButtonChange.bind(this, true);
this.handleButtonChangeSingle = this.handleButtonChange.bind(this, false);

And in the render method:

<Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChangeSingle} >Retour</Button>
<Button href="#" active={this.state.singleJourney} onClick={this.handleButtonChangeRetour}>Single Journey</Button>

The solution that I use to open Popover for components is reactstrap (React Bootstrap 4 components).

    class Settings extends Component {
        constructor(props) {
            super(props);

            this.state = {
              popoversOpen: [] // array open popovers
            }
        }

        // toggle my popovers
        togglePopoverHelp = (selected) => (e) => {
            const index = this.state.popoversOpen.indexOf(selected);
            if (index < 0) {
              this.state.popoversOpen.push(selected);
            } else {
              this.state.popoversOpen.splice(index, 1);
            }
            this.setState({ popoversOpen: [...this.state.popoversOpen] });
        }

        render() {
            <div id="settings">
                <button id="PopoverTimer" onClick={this.togglePopoverHelp(1)} className="btn btn-outline-danger" type="button">?</button>
                <Popover placement="left" isOpen={this.state.popoversOpen.includes(1)} target="PopoverTimer" toggle={this.togglePopoverHelp(1)}>
                  <PopoverHeader>Header popover</PopoverHeader>
                  <PopoverBody>Description popover</PopoverBody>
                </Popover>

                <button id="popoverRefresh" onClick={this.togglePopoverHelp(2)} className="btn btn-outline-danger" type="button">?</button>
                <Popover placement="left" isOpen={this.state.popoversOpen.includes(2)} target="popoverRefresh" toggle={this.togglePopoverHelp(2)}>
                  <PopoverHeader>Header popover 2</PopoverHeader>
                  <PopoverBody>Description popover2</PopoverBody>
                </Popover>
            </div>
        }
    }

THE PROBLEM is here: onClick={this.handleButtonChange(false)}

When you pass this.handleButtonChange(false) to onClick, you are actually calling the function with value = false and setting onClick to the function's return value, which is undefined. Also, calling this.handleButtonChange(false) then calls this.setState() which triggers a re-render, resulting in an infinite render loop.

THE SOLUTION is to pass the function in a lambda: onClick={() => this.handleButtonChange(false)}. Here you are setting onClick to equal a function that will call handleButtonChange(false) when the button is clicked.

The below example may help:

function handleButtonChange(value){
  console.log("State updated!")
}

console.log(handleButtonChange(false))
//output: State updated!
//output: undefined

console.log(() => handleButtonChange(false))
//output: ()=>{handleButtonChange(false);}

I am giving a generic example for better understanding, In the following code

render(){
    return(
      <div>

        <h3>Simple Counter</h3>
        <Counter
          value={this.props.counter}
          onIncrement={this.props.increment()} <------ calling the function
          onDecrement={this.props.decrement()} <-----------
          onIncrementAsync={this.props.incrementAsync()} />
      </div>
    )
  }

When supplying props I am calling the function directly, this wold have a infinite loop execution and would give you that error, Remove the function call everything works normally.

render(){
    return(
      <div>

        <h3>Simple Counter</h3>
        <Counter
          value={this.props.counter}
          onIncrement={this.props.increment} <------ function call removed
          onDecrement={this.props.decrement} <-----------
          onIncrementAsync={this.props.incrementAsync} />
      </div>
    )
  }

I got the same error when I was calling

this.handleClick = this.handleClick.bind(this);

in my constructor when handleClick didn't exist

(I had erased it and had accidentally left the "this" binding statement in my constructor).

Solution = remove the "this" binding statement.


If you are trying to add arguments to a handler in recompose, make sure that you're defining your arguments correctly in the handler. It is essentially a curried function, so you want to be sure to require the correct number of arguments. This page has a good example of using arguments with handlers.

Example (from the link):

withHandlers({
  handleClick: props => (value1, value2) => event => {
    console.log(event)
    alert(value1 + ' was clicked!')
    props.doSomething(value2)
  },
})

for your child HOC and in the parent

class MyComponent extends Component {
  static propTypes = {
    handleClick: PropTypes.func, 
  }
  render () {
    const {handleClick} = this.props
    return (
      <div onClick={handleClick(value1, value2)} />
    )
  }
}

this avoids writing an anonymous function out of your handler to patch fix the problem with not supplying enough parameter names on your handler.


The problem is certainly the this binding while rending the button with onClick handler. The solution is to use arrow function while calling action handler while rendering. Like this: onClick={ () => this.handleButtonChange(false) }


That usually happens when you call

onClick={this.handleButton()} - notice the () instead of:

onClick={this.handleButton} - notice here we are not calling the function when we initialize it


This same warning will be emitted on any state changes done in a render() call.

An example of a tricky to find case: When rendering a multi-select GUI component based on state data, if state has nothing to display, a call to resetOptions() is considered state change for that component.

The obvious fix is to do resetOptions() in componentDidUpdate() instead of render().


From react docs Passing arguments to event handlers

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

Examples related to reactjs

Error: Node Sass version 5.0.0 is incompatible with ^4.0.0 TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type undefined raised when starting react app Template not provided using create-react-app How to resolve the error on 'react-native start' Element implicitly has an 'any' type because expression of type 'string' can't be used to index Invalid hook call. Hooks can only be called inside of the body of a function component How to style components using makeStyles and still have lifecycle methods in Material UI? React Hook "useState" is called in function "app" which is neither a React function component or a custom React Hook function How to fix missing dependency warning when using useEffect React Hook? Unable to load script.Make sure you are either running a Metro server or that your bundle 'index.android.bundle' is packaged correctly for release

Examples related to constructor

Two constructors Class constructor type in typescript? ReactJS: Warning: setState(...): Cannot update during an existing state transition Inheritance with base class constructor with parameters What is the difference between using constructor vs getInitialState in React / React Native? Getting error: ISO C++ forbids declaration of with no type undefined reference to 'vtable for class' constructor Call asynchronous method in constructor? Purpose of a constructor in Java? __init__() missing 1 required positional argument

Examples related to setstate

Can't perform a React state update on an unmounted component How to update nested state properties in React When to use React setState callback React setState not updating state ReactJS: Warning: setState(...): Cannot update during an existing state transition Can I execute a function after setState is finished updating?