korczas
korczas

Reputation: 87

fat arrow componentDidMount

I found in legacy code

componentDidMount = () => {
...
}

I know it is not valid, but it works. Now, I am curious what is the difference between this, and the right way

componentDidMount() {
...
}

Upvotes: 1

Views: 5836

Answers (3)

igorves
igorves

Reputation: 591

Hi basically you can do it, but it's unnecessary and can also hurt performance. Because each time your function does an arrow operation, it has to create a new function object. So it's just an optimization choice.

Good threads and articles:

Upvotes: 8

Dinesh Pandiyan
Dinesh Pandiyan

Reputation: 6299

Arrow functions and function declarations in React work the same way as how they work in vanilla JS.

componentDidMount = () => { // arrow function

and

componentDidMount() { // function declaration

mean the same as these functions are class specific in React. But things get interesting when you see how arrow functions and function declarations behave when you create them and pass them as handlers to other components.

Take a look at this example

export default class Parent extends Component {
  constructor() {
    super();
    this.state = {
      time: new Date().toLocaleTimeString()
    };

    // no function binding necessary

  }

  updateTime = () => { // arrow function used here
    this.setState({ // `this` here will be bound to Parent implicitely
      time: new Date().toLocaleTimeString()
    });
  };

  render() {
    return (
      <div>
        <div>Parent: {this.state.time}</div>
        <button onClick={() => this.updateTime()}>Button in Parent</button>
        <Child
          time={new Date().toLocaleTimeString()}
          updateTimeHandler={this.updateTime}
        />
      </div>
    );
  }
}

// updateTimeHandler will be implicitly bound
// to Parent's context
const Child = ({ time, updateTimeHandler }) => {
  return (
    <div>
      <div>Child: {time}</div>
      <button onClick={() => updateTimeHandler()}>Button in Child</button>
    </div>
  );
};

export default Child;

Now when you don't use arrow,

export default class Parent extends Component {
  constructor() {
    super();
    this.state = {
      time: new Date().toLocaleTimeString()
    };
    // you have to bind the function to this class
    // if you don't, then `this.` in the method
    // will execute in child's context and throw an error
    this.updateTime = this.updateTime.bind(this);
  }

  updateTime() { // function declaration
    this.setState({
      time: new Date().toLocaleTimeString()
    });
  }

  render() {
    return (
      <div>
        <div>Parent: {this.state.time}</div>
        <button onClick={() => this.updateTime()}>Button in Parent</button>
        <Child
          time={new Date().toLocaleTimeString()}
          updateTimeHandler={this.updateTime}
        />
      </div>
    );
  }
}

// updateTimeHandler will execute in Parent's context
// as we explicitly told so
const Child = ({ time, updateTimeHandler }) => {
  return (
    <div>
      <div>Child: {time}</div>
      <button onClick={() => updateTimeHandler()}>Button in Child</button>
    </div>
  );
};

export default Child;

You can play around in this code sandbox and see it for yourself.

https://codesandbox.io/s/j78y87npkv

In addition to this behavior, there are obvious performance differences as quoted in other answers.

Upvotes: 0

Victor Jozwicki
Victor Jozwicki

Reputation: 720

I don't think there is much difference.

But () => {} returns something (implicitly), and I don't think componentDidMount() returns something nor would it be 'better'

So I would write this (as in the docs)

componentDidMount() {
...
}

Upvotes: 0

Related Questions