3

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?

INDRAJITH EKANAYAKE
  • 3,894
  • 11
  • 41
  • 63
trynalearn
  • 39
  • 3

2 Answers2

2

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.

Jared Smith
  • 19,721
  • 5
  • 45
  • 83
rMonteiro
  • 1,371
  • 1
  • 14
  • 37
  • 1
    This is the correct answer, but it could be improved by explaining *why*. – Jared Smith Feb 21 '20 at 10:56
  • @JaredSmith added some explanation, I think it's not the best :/ I could not write it better – rMonteiro Feb 21 '20 at 11:05
  • 1
    That was a pretty good first pass at it. I touched it up for you, let me know if you have any questions or feel free to edit it further yourself if you think something could be clearer. Nice answer. – Jared Smith Feb 21 '20 at 11:12
  • @rMonteiro thanks that works like a charm. Wonder why I didn't try moving the line to the top on my own. However: Should I always put them to the top? Or are there any drawbacks? – trynalearn Feb 21 '20 at 11:34
  • @trynalearn I think there's none drawback by putting the binds in the top, but you only need to do that in cases like this. – rMonteiro Feb 21 '20 at 11:44
1

Please check the code in sandbox: https://codesandbox.io/s/young-architecture-0r1tk

Here you can see that we need to define the method before adding that into state. As first we need to define doAction method then state,as it is used inside state.

Smit Vora
  • 470
  • 3
  • 10