Professionals help: Is my conception true about what happens when a React component is called?

There’s a challenge (Bind ‘this’ to a Class Method) on React certification which includes featuring this keyword and now I’ve thought up a scenario on what happens when a React component is called. Please help me and read my explanation and let me know if it’s correct or not? My explanation includes what happens when you define your component function (class), what happens when you call your component, what this refers to in different occasions, binding and some staff I’ve learned so far on OOP!! Please copy the given code into challenge editor to see the results if you need it. And please if I’m wrong refer to what is wrong using the number in front of each explanation :slight_smile: :pray: :pray::pray::pray::pray::pray::pray::pray::pray:

Here’s the code of React component:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      text: "Hello"
    };
  }
  handleClick() {
    this.setState({
      text: "You clicked!"
    });
  }
  render() {
    return (
      <div>
        <button onClick={this.handleClick}>Click Me</button>
        <h1>{this.state.text}</h1>
      </div>
    );
  }
};

Before looking at what happens when the component is called there are things that happen when defining the component class above:

  • 1- Each class is actually a constructor function which itself is an object from type function. The functions you define inside your class but outside constructor method is defined on the prototype property of the class. So now MyComponent class’s prototype includes handleClick and render.

Now to render the React component we do this:

ReactDOM.render(<MyComponent />, document.getElementById("challenge-node"));
  • 2- When MyComponent is called in the code above, an instance of MyComponent class is instantiated and the newly created instance includes some own properties which one of them is state. But handleClick and render aren’t defined on the instance but as I said on the prototype.

  • 3- After the new instance is created, render method is called on the instance, but render is not an own property so we traverse up the inheritance chain and render exists on prototype and is run. After the markup is returned, our button has a click event listener which instructs to do this: this.handleClick();.

  • 4- Here this refers to the instance but we don’t have handleClick on instance But because of inheritance chain we access handleClick method existing on prototype.

  • 5- So when the button is clicked, the hanleClick method on prototype is run which instructs to do this: this.setState({text: "You clicked!"});

  • 6- This is the explanation I’m not sure to be true. Here this does not refer to anything (is undefined) because we had to travers on inheritance chain! So to prevent this from being undefined we should prevent traversing inheritance chain so we need to provide a handleClick method on the instance itself. So inside the constructor we create a handleClick property and assign it’s value to MyComponent class’s prototype’s handleClick reference but bind it to our instance so we end up to this code:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      text: "Hello"
    };
    //----------binding----------
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState({
      text: "You clicked!"
    });
  }
  render() {
    return (
      <div>
        <button onClick={this.handleClick}>Click Me</button>
        <h1>{this.state.text}</h1>
      </div>
    );
  }
};

And this is what happens after running this.handleClick = this.handleClick.bind(this);

  • 7- There’s 3 this keywords here. All this keywords refer to our instance. First the expression on the right of assignment is run which acceses handleClick property on prototype and binds it to our instance, then this reference is assigned into handleClick own property.

I am certainly no expert here, but I have some thoughts. What you are saying sounds mostly right.

…binding and some staff I’ve learned so far on OOP!!

Keep in mind that JS in not OOP, it is at best OOP-ish. Things like “class” and “this” work differently in JS than they do in other languages that we think of as “true OOP”.

this.handleClick = this.handleClick.bind(this);

  • 7- There’s 3 this keywords here. All this keywords refer to our instance.

Yeah, “this” is a difficult subject. It refers to the execution context. Since we want to make sure that when that method is called it will refer to the class instance, we have to bind it. This is because a function creates its own context.

In a lot of modern React this is not necessary because a lot of people would just use an arrow function now, and they don’t create its own execution context. So, if you had:

  handleClick = () => {
    this.setState({
      text: "You clicked!"
    });
  }

And to be honest, even class-based React is becoming “old-fashioned” in React - more and more people are using functional components with hooks. You still need to know classes because you will work on old code. But in my new code, left to my own devices, I haven’t used a class in over a year. I think that is the direction that React is going. But again, you still need to know how to work with classes.

1 Like

Thank you very much Kevin, I really appreciate it.

This was useful. First I tried to create handleClick method on instance but I used regular functions and it didn’t work but using arrow function works.

I’m not sure if this is a reasonable question but is it possible to use arrow function outside of constructor method? If yes what would syntax look like?

This is outside the constructor method, yes? I was suggesting:

class MyComponent extends React.Component {
  state = {
    text: "Hello"
  };

  handleClick = () => {
    this.setState({
      text: "You clicked!"
    });
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>Click Me</button>
        <h1>{this.state.text}</h1>
      </div>
    );
  }
};

I also got rid of your constructor method. If you don’t provide one, the default constructor will be used.

  constructor(props) {
    super(props);
  }

Since we don’t have to bind our methods anymore and we can set the state property directly as a class property, we usually don’t need a custom constructor and our code is a little cleaner.

1 Like

Oh sorry you’re right.
This would be the last question!

If you define state inside constructor method you create it on actual instance but if you define it outside, you create it on prototype? And in your code in onClick={this.handleClick} this still refers to instance?

What a confusing subject!

I think the state property is on the prototype, but the instance gets its own copy since it is not static.

And this always refers to the execution context. And if you either use binding method or the arrow function, it will be the instance of the class.

Again, be careful with trying to understand JS’s OOP-ish-ness with how other languages implement OOP.

And keep in mind that I’m not an expert on this stuff here - if someone has something smarter to add, that would be good. This is just how I’ve come to understand it.

If you’re into this stuff, the You Don’t Know JS books are great at breaking down the complexities of JS. You can get the md files here for free. (Though I seem to remember getting free ebook or pdf copies somewhere.) He digs very deeply into some of the thornier issues of JS.

1 Like

More info:

1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.