3

Which of the following is the best practice with regard to performance in a React class component:

  1. Binding a call back function in the constructor:

    constructor(props)
    {
        /* some code */
        this.onChange= this.onChange.bind(this)
    }
    
    render() {
       return(
          <div>
              <input onChange={this.onChange}
          </div>
       );
    }
    
    onChange(event) {
    /* some code involving 'this' */
    }
    
  2. Using an arrow function instead of a normal function:

    constructor(props)
    {
        /* some code */
    }
    
    render() {
       return(
          <div>
              <input onChange={this.onChange}
          </div>
       );
    }
    
    onChange = (event) => {
    /* some code involving 'this' */
    }
    
  3. Sticking to a normal function but declaring an arrow function in the onChange field:

    constructor(props)
    {
        /* some code */
    }
    
    render() {
    <div>
        <input onChange={(event) => {this.onChange(event)}}
    </div>
    }
    
    onChange(event) {
    /* some code involving 'this' */
    }
    

Thanks!

nem035
  • 34,790
  • 6
  • 87
  • 99
  • Numbers 2 and 3 might not work the way you'd expect; arrow functions don't bind their own `this`. I'd go with 1. – castis Jan 22 '18 at 16:15
  • 1
    @castis "arrow functions don't bind their own this" That's why 2 and 3 will work exactly as expected :) – Yury Tarabanko Jan 22 '18 at 16:20
  • 1
    The third method is not a good idea, as it creates a new function everytime render is called, you can check this https://stackoverflow.com/questions/45053622/how-to-avoid-binding-inside-render-method/45053753#45053753 also , The first and third method are equivalent – Shubham Khatri Jan 22 '18 at 16:27
  • 1
    FYI, in #3, the constructor initialization is unnecessary because `this.onChange(event)` within the handler causes the calling context to be set correctly anyway. – Patrick Roberts Jan 22 '18 at 16:29
  • You're right, I forgot to delete it after copy-pasting from option 1 :-) –  Jan 22 '18 at 16:34

1 Answers1

4

All 3 options, with regards to this, behave the same.

Option 3 is creating a new function on every render and is thus less desired than options 1 and 2 (since such re-creation is unnecessary and could potentially hinder performance)

As far as options 1 and 2, they come down to the same behavior with slight differences unrelated to the behavior of this.

The trick to understanding why they behave the same with this is to know what the following code does:

method = () => {}

It's just syntactic sugar to add a method to an instance:

class A {
  method = () => {}
}

// is the same as

class A {
  constructor() {
    this.method = () => {}
  }
}

See how Babel transpiles it.

Since an arrow function inherits the context it is defined in as this, the context for option 2 is the class itself.

class A {
  constructor() {
    this.method = () => {
      return this;
      //     ^^^^ this points to the instance of A
    }
  }
}

const a = new A();
console.log(a.method() === a); // true

Which is the same thing for option 1:

class A {
  constructor() {
    this.method = this.method.bind(this);
  }
  method() {
    return this;
    //     ^^^^ this points to the instance of A
  }
}

const a = new A();
console.log(a.method() === a); // true

That means your options come down to the difference between:

// option 1
constructor(props) {
  this.onChange = this.onChange.bind(this)
}

onChange() {
 // code for onChange...
}

and

// option 2
constructor(props) {
  this.onChange = () => /* code for onChange */
}

The main advantage I would give to option 1 is that it has a named function instead of an arrow function, which makes debugging a bit easier when examining stack traces (although function name inferences dilutes this point a bit).

The main advantage I would give to option 2 is that it's a bit "cleaner" looking, as in less verbose, code but that is a subjective opinion.

Overall, option 1 and option 2 are practically indifferent.

nem035
  • 34,790
  • 6
  • 87
  • 99
  • Thanks for the very detailed answer!! So option 1 and option 2 are the same performance wise? –  Jan 22 '18 at 16:29
  • 1
    Yes, in the practical sense. Meaning their perf differences are minimal. Option 1 does have an extra function on the prototype that gets put on every instance when instantiating it but that's just one extra function and shouldn't be an issue. – nem035 Jan 22 '18 at 16:35