Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reactjs: In JavaScript, class methods are not bound by default

I'm following reactjs handling-events documentation, and I came across this:

In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.

What I understand from this quotation is that this doesn't designate the current instantiation in every class methods.

However, if I consider the code below, the method editState can access the property state of the extended class Parent through this. Which would make false the previous quotation, as this is bound to all the class mehtods.

class Parent {
  constructor() {
    this.state = false;
  }
  
  setState(newState) {
    this.state = newState;
  }
}

class Child extends Parent {
  editState() {
    this.setState(true);
  }
}

let c = new Child;
c.editState();
console.log(c.state);

What am I missing here?

like image 927
smarber Avatar asked Sep 18 '17 09:09

smarber


People also ask

Why do we need to bind methods in react?

When we bind the this of the event handler to the component instance in the constructor, we can pass it as a callback without worrying about it losing its context. Arrow functions are exempt from this behavior because they use lexical this binding which automatically binds them to the scope they are defined in.

Why do class methods need to be bound to a class instance?

This is because whenever inside a class component when we need to pass a function as props to the child component, we have to do one of the following: Bind it inside the constructor function. Bind it inline (which can have some performance issues).

Will ES6 classes bind the instance automatically?

[React Component Class] Methods follow the same semantics as regular ES6 classes, meaning that they don't automatically bind this to the instance.

What's an alternative way to avoid having to bind to this in event callback methods?

TL;DR: Binding callbacks is a JavaScript thing. It's necessary because you have to tell your callback what it's context is. Avoid binding by using the public class fields syntax, or bind your callbacks inside the constructor.


2 Answers

When a function is used as an event handler, its 'this' is set to the element the event fired from. As a DOM event handler

like image 87
William Avatar answered Oct 19 '22 03:10

William


I think the React documentation might be misleading. The React component below MyClass is a derived class (aka child class) of React.Component. The constructor method is a special method within javascript ES6 which is used for creating and initializing an object created with a class. React uses the constructor to pass props to the component when the object is created. Base classes (aka parent classes) are created bound to their own this, but the derived classes do not have their own this by default. The derived class must call super(props) which binds the this from the base class down into the derived class.

class MyClass extends React.Component{
    constructor(props) {
       super(props)
    }
}

Here is the relevant information from the link provided by user376830's answer. This is straight from the javascript documentation.

Class context

The behavior of this in classes and functions is similar, since classes are functions under the hood. But there are some differences and caveats.

Within a class constructor, this is a regular object. All non-static methods within the class are added to the prototype of this:

class Example {
    constructor() {
      const proto = Object.getPrototypeOf(this);
      console.log(Object.getOwnPropertyNames(proto));
    }
    first(){}
    second(){}
    static third(){}
}

 new Example(); // ['constructor', 'first', 'second']

Note: Static methods are not properties of this. They are properties of the class itself.

Derived classes

Unlike base class constructors, derived constructors have no initial this binding. Calling super() creates a this binding within the constructor and essentially has the effect of evaluating the following line of code, where Base is the inherited class:

this = new Base();

Warning: Referring to this before calling super() will throw an error.

Derived classes must not return before calling super(), unless they return an Object or have no constructor at all.

class Base {}
    class Good extends Base {}
    class AlsoGood extends Base {
    constructor() {
        return {a: 5};
    } 
 }

class Bad extends Base {
    constructor() {}
}

new Good();
new AlsoGood();
new Bad(); // ReferenceError
like image 2
jyapx Avatar answered Oct 19 '22 05:10

jyapx