Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript React Basics (retired) Stateful Components Updating State

Can’t set state of null

My code can be found here: http://codepen.io/hum4n01d/pen/apzBwP

I’m getting

app.jsx:37 Uncaught TypeError: Cannot read property 'setState' of null(…)

/cc Guil Hernandez because I can’t cc Jim for some reason

3 Answers

andren
andren
28,558 Points

Remember the bit in the video where Jim talks about React automatically binding the "this" keyword so that you don't have to manually bind it when calling methods? Well that fact is only true when you use "React.createClass" to create the component classes.

If you use ES2015 style classes like you have done (which is now the officially recommended way of creating components) then you don't get any autobinding. Meaning that you do in fact need to bind "this" like is demonstrated in the video.

The simplest way of dealing with this is to add .bind(this) to methods called in your render method, so changing your render code to this:

render() {
        return (
            <div className="counter">
                <button className="counter-action decrement"> - </button>
                <div className="counter-score">{this.state.score}</div>
                <button className="counter-action increment" onClick={this.incrementScore.bind(this)}> + </button>
            </div>
        )
}

As an example will fix your issue, binding this in the render method is not the most efficient way of dealing with the issue though, since that causes you to rebind it each time the component is rendered. It is considered to be a better practice to instead bind the method in the constructor of the component, that is done with code like this:

constructor(props) {
        super(props)
        this.incrementScore = this.incrementScore.bind(this)
        this.state = {
            score: 0
        }
    }

Changing your constructor to the above will also fix your issue, above you bind this when the component is created, since the code in the constructor only runs once it is more efficient than placing the binding in the render method.

Ha wow! I literally just found this and responded to my own post and literally as I pressed submit, I got a notification (email) with your response!

Thank you, this is really helpful and thanks for taking the time to explain it! Kudos and 12 points to you!

andren
andren
28,558 Points

Yep the moment I posted my solution I saw that you had already figured it out. Honestly though I'm pretty impressed that you managed to figure out the fix so quickly, I was only able to answer so quickly because I have encountered this problem in the past and ended up doing a bunch on research on it at that point.

The issues around binding is one of the many reasons why I strongly disagree with Treehouse's choice of not using ES2015 class components in this course, since "React.createClass" is no longer officially recommended its unlikely that people will be able to continue using this syntax when working on proper apps in the real world. So learning how to properly use the ES2015 syntax, and the issues surrounding it like the binding issue is pretty important for people just beginning out with React. Even though it is a bit more complicated than the "React.createClass" method.

andren , I think that the course was made before they decided to start using es6. Looks like we’re all going to have to retake all the js courses to get credit since they’ll be rewritten :(

andren
andren
28,558 Points

hum4n01d, Treehouse had not adopted ES6 yet, but ES6 style components had been standard for a while by the time this course came out. It is a relatively recent course, just around 4 months old, it was something that annoyed me at the time it was released as well.

Treehouse generally doesn't reshoot courses often so I doubt this course will be refreshed for quite a while yet.

oh D:

Ok well I figured it out by Googling, reading documentation, but mostly guessing. It was pretty unclear though. I needed to bind the function call to this on the button click. This was the button code I needed:

<button className="counter-action increment" onClick={this.incrementScore.bind(this)}> + </button>

See the following for the different ways binding can occur with es6 see: http://egorsmirnov.me/2015/08/16/react-and-es6-part3.html