Use Class Components with React

    Kent C. DoddsKent C. Dodds

    In this lesson we'll look at a few ways to deal with issues around this when writing class components with React. We'll eventually land at Public Class Fields syntax which is a stage 3 proposal in the ECMAScript standardization process.



    Become a Member to view code

    You must be a Member to view code

    Access all courses and lessons, track your progress, gain confidence and expertise.

    Become a Member
    and unlock code for this lesson


    Instructor: 00:00 Here we have a class counter that extends a React component. Inside the constructor, we're forwarding along all the arguments to super and then initializing our state with count zero. Then in our render method, we just render a button that has an on click that updates our state to increment the count. Then it renders our state inside the button.

    00:18 This is totally fine to have an arrow function right here, but sometimes it can get a little bit big. In some cases, it can actually be a performance bottleneck. So we're going to go ahead and extract that. We'll call this handle click on our class here. We're just going to pull this out to our handle click. Then we'll say this.handle click. I'll save it.

    00:39 We'll see that it actually is broken. If I pop open my developer tools, we're going to get this error message every single time saying, "Cannot read property. Set state of undefined." The line that this is breaking on is right here where we're calling set state on this. The problem is pretty fundamental in JavaScript.

    00:56 Let's take an example here. If I were to make a var Bob object and this has a name of Bob and greet that accepts a name, then we return, "Hi, name. My name is" Then we close off that object. Then we say Bob.greet Jane. We're going to say, "Hi, Jane. My name is Bob." What we're doing here though is we're passing on click this reference to this function. So let's go ahead and get a reference to Bob.greet with the greet function equals Bob.greet.

    01:34 Then later on, React is going to come around and call the function that we've passed it. Let's go ahead and do greet function. We'll call it with Jane. We're going to get, "Hi, Jane. My name is blank." That's because when this function called, this is not referencing our object Bob.

    01:51 We can get around this problem in JavaScript by instead assigning this to bind Bob. Now this will always be referencing our Bob function. If we call that again, we're going to see, "Hi, Jane. My name is Bob." We can solve this problem by calling .bind with this. We save. Now our functionality is totally working.

    02:14 That's great. It cleans up our render function a little. But it's kind of annoying to have to call .bind. It also actually is still performance bottleneck in some situations which would be nice to avoid. What we can do is, inside of our constructor, say this.handle click. We reference this.handle click which actually is pointing to the prototypal method here.

    02:35 We're going to actually reassign this to this.handle click.bind this. We're creating new function inside of our constructor and overriding the function that we have reference to from our prototype to a pre-bound method. Now we can just pass this without the bind, and everything works perfectly.

    02:54 That's better. We're getting rid of that performance bottleneck, but this is still super annoying, especially if you have a lot of these.

    03:01 One really neat trick is we can actually use public class fields. Let's go ahead, and we'll remove these and move these down outside of the constructor. Now our constructor looks exactly like the default constructor, so we can get rid of that. This is using public class fields where we have the name of the field and then the assignment and then the value that it'll be assigned to.

    03:20 Now if we save this, everything else is working exactly as it was before. We've gotten rid of a little bit of boiler plate using public class fields. We can actually do a little bit better by not creating this handle click method on the prototype at all and just having it on the instance. Here we can say, "Handle click equals a function that we bind to this." Now we can get rid of that. Everything is working yet again, just perfect.

    03:47 But having this bind on here is super annoying also. So we're going to get rid of that and just use the lexical this that arrow functions give us. Everything is working perfectly there too.

    03:57 Now we've been able to clean up our render method and avoid a potential performance bottleneck by moving our event handler to the class body and using public class fields. We got rid of that constructor. We're using this public class field syntax. Then we're using an arrow function to avoid issues with using this inside of our event handler.