The difference between Classes and Function components in React
Tags: react, javascript, webdev
Published: 2020-04-22 01:21:20

<p>In the <strong>early days</strong> of React, <strong>Classes</strong> were the only way to have <strong>functionality</strong> in your components (like state). You’d only use <strong>Functions for dumb components</strong> which only displayed stuff.</p><p>This is no longer true, because we now have <a href="https://reactjs.org/docs/hooks-intro.html"><strong>React Hooks</strong></a> and they allow us to have in Function components the same functionality we used to have with Classes.</p><p>However, there is <strong>one key difference</strong>, that not everyone is aware of 🔮</p><h3>Let’s start with a simple example</h3><p>The best way to understand this concept is by <strong>seeing it in action.</strong></p><p>Let’s create a simple app where you can <strong>select</strong> a Simpsons’ character from a list. Then when you press a <strong>button</strong>, an <strong>alert</strong> will show a greeting to that character <strong>after 4 seconds</strong>.</p><p>We will create the SayHi<strong> </strong>component<strong> </strong>as a Class and also as a Function, to see the <strong>difference</strong>.</p><h3>Our two SayHi components</h3><p>First, let’s write our Function component:</p>

```javascript
import React from "react";

const SayHiFunction = ({ name }) => {

  const handleClick = () => {
    setTimeout(showAlert, 4000);
  };

  const showAlert = () => {
    alert(`Hello ${name}!`);
  };

  return (
    <div>
      <button onClick={handleClick}>
        Say Hi with Function
      </button>
    </div>
  );
};

export default SayHiFunction;
```

<p>As you can see, it’s a very simple component. It receives <strong>name as a prop</strong>, and then when you <strong>click</strong> the button, a <strong>timeout</strong> is set to show the <strong>alert after 4 seconds.</strong></p><p>Now let’s transform this Function into a Class:</p>

```javascript
import React, { Component } from "react";

class SayHiClass extends Component {

  handleClick = () => {
    setTimeout(this.showAlert, 4000);
  };

  showAlert = () => {
    alert(`Hello ${this.props.name}!`);
  };

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>
          Say Hi with Class
        </button>
      </div>
    );
  }
}

export default SayHiClass;
```

<p>Pretty easy, right? I’m sure almost anyone with some React knowledge would be able to do this transformation.</p><p>You can play with the app here:</p>

{%codesandbox class-vs-function-vppoj %}

<p>However, <strong>this two components will not behave the same 😕</strong></p><h3>So what’s the difference?! 😠</h3><p>Ok, the important part. Let’s do this:</p><ul><li>Select “<em>Marge</em>” from the list</li><li>Press the button</li><li><strong>Change</strong> the character to “<em>Homer</em>” <strong>before</strong> <strong>4 seconds</strong> pass</li></ul><p>What do you expect to happen? <strong>Do you expect the alert to say “<em>Hello Marge” </em>or “<em>Hello Homer”</em>?</strong></p><p>Again, right now the important thing is not what you <em>think</em> will happen, but what would you <strong><em>expect</em></strong> to happen in this case.</p><p>Of course, <strong>we would expect to see “<em>Hello Marge”</em></strong>. That was the <strong>selected</strong> <strong>character</strong> <strong>when we pressed the button.</strong></p><p>Now that we’re on the same page on that, what do you think <strong><em>will</em></strong> happen?</p><p>Let’s take a look at the Function component first:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1yqvTEO3OFCDnk1Ts52eQQ.gif" /></figure><p>Good! <strong>It behaves as we expected</strong> and the alert says “<em>Hello Marge”</em>.</p><p>Let’s try the Class component now:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Wdd4sToiQhvpoB7bbyHJuA.gif" /></figure><p>Mmm, that was <strong>not what we expected</strong>. We changed the selected character after pressing the button, and the alert message also changed 🤔</p><h3>What the f*%! happened?</h3><p>Well, <strong>our two components are not</strong> <strong>the same. </strong>Of course, one is a Class and the other is a Function, but <strong>we also made a mistake when we transformed</strong> the Function into a Class.</p><p>The example seemed obvious and straightforward, and that’s the transformation most people would do. <strong>It’s common to think those two pieces of code are equivalent.</strong> However, it’s wrong because of the <strong>main difference between Classes and Function components</strong>:</p><blockquote><strong>Function components capture the rendered values.</strong></blockquote><h3>What does that mean?</h3><p>Let’s analyze our example to understand this.</p><p>When we used the Class component, <strong>the alert message</strong> <strong>changed</strong> after we changed the selected character.</p><p>That happens because <strong>our method is reading from </strong><strong>this.props.name</strong>.</p><p><em>But props are immutable in React, that’s not the issue.</em></p><p>It’s true, props are immutable, but… <strong>this is mutable</strong>. And it makes sense, because <strong>React mutates </strong><strong>this over time so you can read the fresh version</strong> in render and lifecycle methods.</p><p>So in our example, by changing the selected character the second time, we <strong>re-render</strong> the component, so <strong>this.props is updated</strong>. The method is <strong>reading from the latest, newest props.</strong></p><p>That’s a problem because we weren’t expecting that. <strong>We would expect our event handlers to be “linked” to a particular render, with particular props.</strong></p><p>By setting a timeout whose callback reads this.props, we’re making that impossible. <strong>Our callback will not be “linked” to a particular render</strong>, so it doesn’t know what the “correct” props are.</p><p>We don’t have this issue with the Function component because, once again:</p><blockquote>Function components capture the rendered values.</blockquote><p>That means that even if we change the character a second time, the method <strong>will display the alert using</strong> <strong>the selected character when the button was pressed</strong>, because that value was <em>captured</em>. Unlike this, the props<strong> </strong>are<strong> immutable so the object is never mutated by React.</strong></p><p>When the parent component renders SayHiFunction with different props, React will call the SayHiFunction again. But<strong> the event handler we already clicked is “linked” to the previous render with its own </strong><strong>name value and the </strong><strong>showAlert callback that reads it.</strong></p><h3>So Classes are useless?</h3><p>No! Not at all. Classes are fine, we’re having a bug here because <strong>our implementation is incorrect, different from the original function component.</strong></p><p>If you don’t want to use a Function component, there are many ways to fix this issue. For example, you could do this:</p>

```javascript
import React, { Component } from "react";

class SayHiClass extends Component {

  handleClick = () => {
    const { name } = this.props;
    setTimeout(() => this.showAlert(name), 4000);
  };

  showAlert = (name) => {
    alert(`Hello ${name}!`);
  };

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>
          Say Hi with Class
        </button>
      </div>
    );
  }
}

export default SayHiClass;
```

<p>Our props were getting “lost” before, so in this case we are reading and <strong>capturing them early during the event.</strong></p><p>Again, this is just one way of fixing it, there are many others but that’s not the focus of this post.</p><h3>That’s it!</h3><p>I hope this post was useful and now you understand the main key difference between Classes and Function components.</p><p>Thanks for reading ❤️</p>