Enter Your Email Address to Watch This Lesson

Your link to unlock this lesson will be sent to this email address.

Unlock this lesson and all 962 of the free egghead.io lessons, plus get JavaScript content delivered directly to your inbox!



Existing egghead members will not see this. Sign in.

Public Class Fields with React Components

4:52 JavaScript lesson by

Public Class Fields allow you to add instance properties to the class definition with the assignment operator (=). In this lesson, we'll look at their use case for simplifying event callbacks and state initialization with a React component.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

Public Class Fields allow you to add instance properties to the class definition with the assignment operator (=). In this lesson, we'll look at their use case for simplifying event callbacks and state initialization with a React component.

Avatar
Vamshi

Excellent video. But why in 2017? :D
I wish this came out in 2015/2016

Avatar
Kent C.

Haha! Yeah, it's probably good to note that Public Class Fields are still relatively new. Stage 2 stuff!

In reply to Vamshi
Avatar
David

After many puzzlings of "why this way? Dunno, it works" ... thanks for the light bulb moment!

Avatar
Kent C.

I'm glad it was helpful!

In reply to David
Avatar
Gary

Can you tell me is there a way to enable Public Class Fields in standardjs eslint

Avatar
Kent C.

Sorry, I don't use standard. I have my own eslint config and I use the babel-eslint parser to get linting on upcoming features like this.

In reply to Gary
Avatar
Vamshi

Kent, I was trying this out today

import React, { PropTypes, Component } from 'react';
import Loading from 'gssp-common-lib/lib/components/gssp/leafs/loading/loading.component';

class SurveyQuestions extends Component {
  componentWillMount = () => {
    this.props.overrideEmit('surveyquestions');
  }
  render() {
    return (
        <div>
        {this.props.loading ? <Loading /> : null}
          <h2> Hello World </h2>
        </div>
    );
  }
}

export default SurveyQuestions;

This is undefined. Can you please tell me what Im missing here?

In reply to Kent C.
Avatar
Kent C.

Perhaps I should have mentioned this, but you don't want to do this for lifecycle methods that React will call with your instance. You'll want to use public class fields sparingly.

In reply to Vamshi
Avatar
Gary

Hi Kent,
Found a way,i just had to install babel-eslint and add "parser": "babel-eslint" in .eslintrc file , thanks a lot

In reply to Kent C.
Avatar
Enrique

Loved the video. I found it doing a search within Egghead, and I'd like to see the rest of the course that this video belongs to. Do you happen to know which course this video is a part of?

Avatar
Kent C.

Hi Enrique,
It's actually not part of a course. This was just a one-off video I made. Sorry about that!

In reply to Enrique
Avatar
Enrique

No worries! I was assuming that every video was part of a course. Glad I searched for it! It's good!

In reply to Kent C.

Here we have a basic react component called "App." In its constructor, it is initializing some state. In the render method, we're rendering out the Click Count. That's the current state of the clicks, as well as a button called "Click Me!" that passes the handleClick handler to the onClick callback.

Here in handleClick where you setState and we increment clicks. Here there's a problem if we go ahead and click, then we're going to see an error "this.setState is not a function." That's because we're passing handleClick to this onClick callback.

When react is calling our our onClick callback with the event, it's not calling it with the right context. This is not actually bound to anything at all. That's why we're getting this "this.setState is not a function."

This is pretty easy to solve. Most people will just make this an arrow function. Then you'll have to invoke this. Now if we click, we'll see that the click count is incrementing.

There are a couple of drawbacks to this. First of, if you want to pass on the event, now you have to type "event" here and "event" here so that you can get access to the event. Another issue there is if there are multiple parameters, then you have to say "param2," then you'll have to go here and "param2."

It won't be long before you start just saying, "The heck with it." We'll say "args" and "...args" so that you don't have to keep in adding parameters, or whatever. But this is not really ergonomic. I don't really like doing things this way.

Another way to accomplish this same kind of idea is instead of using arrow function, which doesn't have at this binding and simply uses this binding of its closure, we'll say ".bind this," so we specify that this binding for the function explicitly. This works just as well and you don't need to worry about parameters or any arguments or anything.

That's great, but I still don't really like having to do the binding here. It also suffers from the performance issues with the arrow function where you're creating a new function every single time the render method is called, which is actually a lot of times often in react components.

Instead of doing the binding here, we can actually do the binding in our constructor. We can say "this.handleClick = this.handleClick.bind this." What this does effectively is it overwrites these instances of handleClick with a bound version of handleClick so that you can pass it on.

It doesn't matter how it's being called. It's always going to be bound with this, with our instance of the component. That works great.

Let's say that you have many handleClick or of handle key up or handle mouse over, you have a bunch of these in your component. Now you have to have not only the definition, but also a line in your constructor binding that definition. That's also not super ergonomic.

With public class fields, you can actually solve this problem by basically taking this assignment looking operator and sticking it right here in the class definition. Then we'll need to turn this into a function, and then we want to have this function be bound to this. Then we'll comment this out.

Because we have this assignment syntax here, the public class field specification basically says, "Postpone evaluating this expression until each instance is being constructed." We're going to add a handleClick property on each instance and assign it to this expression.

This runs effectively. It runs in the controller effectively. You're doing the same type of thing as this would do as we had before.

Now we can click and that works just fine. We can make this even a little bit more ergonomic by removing the binding here and just going with lexical binding for this using an arrow function. Now, we can click and increment and everything works nicely with public class fields.

We can do the same things with state. We'll just copy and paste the state assignment and put it as part of the class definition. Now that state assignment will take place when the instance is being constructed as well.

We'll get rid of this, have that commented out. You'll see that the click count is still initialized to zero. If we initialize it to six, then that works just fine.

Now you can see that the constructor is totally useless. It's not really doing anything at all. We can get rid of that entirely and have our App component still function exactly as we want it to.

That's public class fields. It's simply the name of the property, and then the "equals" operator. Then the expression that we want to have it initialize to when each instance is being initialized.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?