Search code examples
javascriptreactjsreact-state-management

React: Error referencing a function within state


the problem seems simple, but I can't figure out how to solve it:

  • Add-Button declared within the render-Function works just fine
  • Add-Button declared within the state itself doesn't work. As the code already mentions, it will throw the "TypeError: Cannot read property 'state' of undefined"-Error
class App extends Component {
  constructor() {
    super();

    this.state = {
      someArrayOfObjects: [{
          attr: 
             // SNIP ...
                // Doesn't work!
                // When clicked leads to this error: "TypeError: Cannot read property 'state' of undefined"
                <button onClick={this.doAction}>Add</button>
             // SNIP ...
        }]
    };

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

  // SNIP ...
  doAction() {
    console.log(this.state);
  }

  render() {
      return(
          // SNIP...
          // Works just fine
          <button onClick={this.doAction}>Add</button>
      )
  }
}

What am I missing out?


Solution

  • You need to bind the function doAction before the state

    constructor() {
        super();
    
        this.doAction = this.doAction.bind(this);
    
        this.state = {
          someArrayOfObjects: [{
              attr: 
                 // SNIP ...
                    // Doesn't work!
                    // When clicked leads to this error: "TypeError: Cannot read property 'state' of undefined"
                    <button onClick={this.doAction}>Add</button>
                 // SNIP ...
            }]
        };
    
      }
    
    

    Edit: You need to bind the function before the state creation. At the point at which you are creating the button in the state, this.doAction refers to the prototype method of the component class. But you can't pass a method as a callback directly, so you need to bind it. Function.prototype.bind creates a new function, which you then assign to the instance being created in the constructor:

    this.doAction = this.doAction.bind(this);
    

    So, perhaps confusingly, this.doAction refers to two different functions at different points in the code. You want to pass the bound version to the handler (see link above for why), so you need to bind it before creating that button.