React 16.3 class method vs constructor method

I'm learning React 16.3, and it's new Context API. In particular Updating Context from a Nested Component. In their example they set a method that is defined in the constructor rather than a standard method.

class App extends React.Component {
  constructor(props) {
    super(props);

    // What is the benefit of doing this here?
    this.toggleTheme = () => {
      this.setState(state => ({
        theme:
          state.theme === themes.dark
            ? themes.light
            : themes.dark,
      }));
    };

    this.state = {
      theme: themes.light,
      toggleTheme: this.toggleTheme,
    };
  }

  render() {
    // The entire state is passed to the provider
    return (
      <ThemeContext.Provider value={this.state}>
        <Content />
      </ThemeContext.Provider>
    );
  }
}

Everything I've read regarding lifting state up and passing methods down to children has been done using the below pattern. Why is the above preferred over the below? Are there any differences?

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      theme: themes.light,
      toggleTheme: this.toggleTheme,
    };
    this.toggleTheme = this.toggleTheme.bind(this);

  }

    // Could it be done here?
    toggleTheme() {
        this.setState(state => ({
            theme:
                state.theme === themes.dark
                ? themes.light
                : themes.dark,
        }));
    };


  render() {
    // The entire state is passed to the provider
    return (
      <ThemeContext.Provider value={this.state}>
        <Content />
      </ThemeContext.Provider>
    );
  }
}

2 answers

  • answered 2018-05-16 05:32 Mateo Hrastnik

    The difference between this two approaches:

    class MyComponenet extends React.Component {
        constructor(props) {
            super(props);
    
            this.method = () => {
                console.log('Method');
            }
        }
    
        render() {
            return null;
        }
    }
    

    ... and ...

    class MyComponenet extends React.Component {
        method() {
            console.log('Method');
        }
    
        render() {
            return null;
        }
    }
    

    Is that the first approach defines the method with the arrow notation which automatically binds the function's this to be the instance of the component class while the other doesn't.

    You could change the second example to:

    class MyComponenet extends React.Component {
        method = () => {
            console.log('Method');
        }
    
        render() {
            return null;
        }
    }
    

    This would be the same as the first example, but keep in mind you have to enable your transpiler option that allows this syntax.

  • answered 2018-05-16 05:36 Dummy

    If you use the first approach which is defining the method inside the constructor like this

    constructor() {
        this.toggleTheme = () => {
          this.setState(state => ({
            theme:
              state.theme === themes.dark
                ? themes.light
                : themes.dark,
          }));
        };
    }
    

    Then when your component usesthis.toggleTheme as a callback, you don't have to bind its this reference to the current component in which it is defined, e.g. this.toggleTheme = this.toggleTheme.bind(this), on the other hand, if you define toggleTheme as a method outside the constructor as in your second example, and if toggleTheme is passed as a callback, you will get "setState is not defined" or something like that when toggleTheme is invoked

    Also, with the first approach toggleTheme is added as a instance property to the component class meaning each component instance will have a separate copy of toggleTheme, whereas the second approach will add it to the prototype of the component class which is better in terms of memory consumption because all component instances will share that method on the prototype