Class Components vs Functional Components in React
Tags: react, javascript, beginners
Published: 2021-07-11 08:19:43

Disclaimer: This article is not about which components are better, but more of a discussion on the differences. 

When I started learning React with my bootcamp, we mainly focused on using class components -- if there is initial state, and presentational components if we are just grabbing props. I heard of functional components, but never felt comfortable using it until I started learning Hooks (Remember you can only use Hooks in functional components, not class components).

Let's break down the syntax difference in each of these components!

--- 

<h2>Difference 1: Rendering JSX</h2>

<h3>🕹 Syntax 🕹</h3>

**Class Component (without ES6 destructuring)**
```javascript
import React from 'react';

class App extends React.Component {
  render() {
    return <h1>Hello, World!</h1>;
  }
}
```

**Functional Component**
```javascript
import React from 'react';

function App() {
  return <h1>Hello, World!</h1>;
}
```

<h3>🍳 Breakdown 🍳</h3>

As you can see above, there are a couple obvious differences in functional component: 
1. We don't need to extend a component 
2. We also don't need to use the `render` keyword. 

<strong>Q</strong>: Why do we need to extend the `React.Component` class in class component?
<strong>A</strong>: In React, by extending the `React.Component` class, it allows us to pass props to a user defined class/component and inherit methods from `React.Component` class, like the lifecycle methods (`componentDidMount`, `componentDidUpdate`, `componentWillUnmount`, `render`) and `setState`.

<h3>📝 Note 📝</h3>
In case you don't know, `render` is one of the lifecycle methods and the only required method in a class component. It would examine `this.props` and `this.state` and return types like React elements (JSX), array and fragments, etc. Do not expect it will modify component state! 

The React documentation has a very precise and clear explanation on the `render` method, as well as the rest of the lifecycle methods. [here](https://reactjs.org/docs/react-component.html#render)

<h3>⭐️ Additional Note ⭐️</h3>
Here's a rule of thumb 👍🏻: 
If you only have the render method in your class component, use functional component (which is referred as stateless component sometimes) instead. In functional component, everything defined in the function's body is the render function which returns JSX in the end. 

That's how Hooks comes in place as well. In case you want to make a state change in that functional component, you can easily add it without changing to class component by using `useState` and `useEffect` for lifecycle methods (will cover that in a bit!).

<h3>Resources</h3>
- [Extending React](https://www.javascriptjanuary.com/blog/extending-react) (JavaScript January)
- [Why we do extends React.Component when creating the class component in React?](https://stackoverflow.com/questions/52585851/why-we-do-extends-react-component-when-creating-the-class-component-in-react) (Stack Overflow)

--- 

<h2>Difference 2: Passing Props</h2>

<h3>🕹 Syntax 🕹</h3>

Let's say we have a props `name` from this `Component`: <br/>`<ExampleComponent name="Megan" />`

**Class Component**
```javascript
class ExampleComponent extends React.Component {
  render() {
    const { name } = this.props;
    return <h1>Hello, { name }!</h1>
    
   // or without destructuring, it will look like this:
   // return <h1>Hello, { this.props.name }!</h1> 
  }
}
```

**Functional Component**
```javascript
// with destructuring
const ExampleComponent = ({ name }) => {
  return <h1>Hello, { name }!</h1>
}

// without destructuring
const ExampleComponent = (props) => {
  return <h1>Hello, { props.name }!</h1>
}
```

<h3>🍳 Breakdown 🍳</h3>

In **class component**, since it is a class, we have to use `this` to refer to the props, or we can destructure it to get `name` inside props. Or if we have multiple props, we can do that too: 
```javascript
class ExampleComponent extends React.Component {
  render() {
    const { name, age, occupation } = this.props;
    return (
      <div>
         <h1>Hello, { name }!</h1>  
         <p>I am { age } yo and I work as a { occupation }.</p>
      </div> 
    )
}
```

As for **functional components**, we are passing props as an argument of the function. Same as above, if we have mutliple props, we can do this:
```javascript
// with destructuring
const ExampleComponent = ({ name, age, occupation }) => {
  return (
      <div>
         <h1>Hello, { name }!</h1>  
         <p>I am { age } yo and I work as a { occupation }.</p>
      </div> 
  )
}

// without destructuring
const ExampleComponent = (props) => {
  return return (
      <div>
         <h1>Hello, { props.name }!</h1>  
         <p>I am { props.age } yo and I work as a { props.occupation }.</p>
      </div> 
  )
}
```

---

<h2>Difference 3: Handling and Updating state</h2>

Before React 16.8 (released in Feb 2019), class component was the only component that can handle state. With the introduction of Hooks and its `useState` in React 16.8, we can handle state in functional component! *yay!* 

In case you are not familiar with Hooks and wondering what so special about this *Hooks* thing, this [Intro to Hook](https://reactjs.org/docs/hooks-intro.html) from React documentation explains pretty thoroughly. 

(Off topic: I personally enjoy reading the React documentation because they are able to explain the most technical concepts in a not so robotic and boring tone, really unlike a lot of the documentations I have read. I highly recommend you to spend some time reading the doc!)

<h3>🕹 Syntax 🕹</h3>

**Class Component**
```javascript
class ExampleComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
      name: "Megan"
    };
  }
  
  // or you can write this without constructor():
  // state = {
  //  count: 0,
  //  name: "Megan"
  // };

  render() {
    return (
      <div>
        <h1>Hello, {this.state.name}</h1>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click to add 1
        </button>
      </div>
    )
  }
}
```

Alternatively, you can write the function inside `onClick` event before `render()`:
```javascript
class ExampleComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
      name: "Megan"
    };
  }
  
  // or you can write this without constructor():
  // state = {
  //  count: 0,
  //  name: "Megan"
  // };

  handleClick = () => {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return (
      <div>
        <h1>Hello, {this.state.name}</h1>
        <button onClick={this.handleClick}>
        // or <button onClick={() => this.handleClick()}>
          Click to add 1
        </button>
      </div>
    )
  }
}
```

**Functional Component**
```javascript
// by the way, I don't want to continue this without explanation
// This is the arrow function, in case you are not familiar
// Alternatively, you can also write 
// function ExampleComponent()
// They are basically the same thing.


import React, { useState } from 'react';
// ES6 destructure ^

const ExampleComponent = () => {
  const [count, setCount] = useState(0);
  // or without destructuring, this will be React.useState(0)

  return (
    <div>
      <h1>Hello, {this.state.name}</h1>
      <button onClick={this.handleClick}>
      // or <button onClick={() => setCount(count + 1)}>
         Click to add 1
       </button>
    </div>
  )
}
```

<h3>🍳 Breakdown 🍳</h3>

In **class component**, we can access the value of the state by using `this.state` inside JSX and we would use `setState` to update the value of the state. You can set the function inside the event or outside of the render() method -- for readability.

In **functional component**, we would use `useState` to assign initial state and we would use `setCount` (in our example) to update the state. If we want to access the value of the state, we can omit `this.state` and call the name of the state instead, in our case, it would just be `count`.

<strong>Q</strong>: What's with the square bracket, like `[count, setCount]`? 
<strong>A</strong>: The `[count, setCount]` syntax is called "array destructuring"!! We are basically making two new variables, in other words, 
```javascript
let countVariable = useState(0);
let count = countVariable[0];
let setCount = countVariable[1];
```

This can be quite confusing by accessing with `0` and `1` as they have a specific meaning, so React use the "array destructuring" instead. 

This is simply the highlight I got from the React documentation, here's the [section](https://reactjs.org/docs/hooks-state.html#tip-what-do-square-brackets-mean) where you can read in details!

---

Last but not least...
<h2>Difference 4: Lifecycle Methods</h2>

`useEffect` is the combination of `componentDidMount`, `componentDidUpdate` and `componentWillUnmount`. 

<h3><code>componentDidMount</code></h3>
It is invoked immediately after a component is mounted (Mounting means when an instance of a  component is being created and  inserted into the DOM -- [React Doc](https://reactjs.org/docs/react-component.html#mounting)).

<h3>🕹 Syntax 🕹</h3>

**Class Component**
```javascript
class ExampleComponent extends React.Component {
  this.state = {
    data: []
  }
  componentDidMount() {
    fetch(someUrlHere)
      .then(res => res.json())
      .then(data => this.setState(data))
  }
  
  render() {
   ...
  }
}
```

**Functional Component**
```javascript
const ExampleComponent = () => {
  const [data, setData] = useState([]);

  useEffect(() => {
    fetch(someUrlHere)
      .then(res => res.json())
      .then(data => setData(data))
  }, []);
  
  return (
    ...
  )
}
```

<h3>🍳 Breakdown 🍳</h3>

In **class component**, `componentDidMount` is only called once after the first render.

In **functional component**, we replace `componentDidMount` with `useEffect`. As we can see there's a `[]` in the second argument, we usually would put some state we like to update/change, let's say you want to restart a quiz app. `useEffect` will only be called if there's any selected changes. 

In our case right now, since it is an empty array, `useEffect` will be called once on mounting, similar to `componentDidMount`.

As you can see in both components, we can set state inside the methods.


<h3>Further Reading</h3>
- If you are interested in seeing how useEffect works with fetching data using async/await and axios, here's a great [article](https://www.robinwieruch.de/react-hooks-fetch-data)

👩🏻‍💻**Author's Note**: I am not so sure how to demonstrate the `componentDidUpdate()` and `useEffect()`. If you are interested, I am attaching this [link](https://reactjs.org/docs/hooks-effect.html#example-using-classes) from React Doc, this [Stack Overflow post](https://stackoverflow.com/questions/53255951/equivalent-to-componentdidupdate-using-react-hooks) and [How to mimic componentDidUpdate() with React Hooks](https://dev.to/savagepixie/how-to-mimic-componentdidupdate-with-react-hooks-3j8c) from another dev.to writer. Based on my quick research, it looks like we may need `useRef()` and custom hook, which currently is out of my knowledge range at the moment.👩🏻‍💻 

<h3><code>componentWillUnmount</code></h3>
It is invoked immediately before a component is unmounted and destroyed. It is usually used for performing any necessary cleanups. One of the most straightforward examples is clear an interval (`clearInterval` duh).

<h3>🕹 Syntax 🕹</h3>

(Code reference from this [Stack Overflow post](https://stackoverflow.com/questions/49906437/how-to-cancel-a-fetch-on-componentwillunmount))

**Class Component**
```javascript
class ExampleComponent extends React.Component {
  this.state = {
    data: []
  }

  // say we have a mounted function that returns a boolean
  mounted = () => {
   ...
  }

  componentDidMount() {
    this.mounted = true;
    
    fetch(someUrlHere)
      .then(res => res.json())
      .then(data => {
         if (this.mounted)) {
            this.setState(data)
         }
      })
  }

  componentWillUnmount() {
    this.mounted = false;
  }
  
  render() {
   ...
  }
}
```

**Functional Component**
```javascript
const ExampleComponent = () => {
  const [data, setData] = useState([]);

  useEffect(() => {
    let isMounted = true;

    request.get(url)
      .then(result => {
        if (isMounted) {
          setData(result);
        }
      });
     return () => {
        isMounted = false;
     };
   }, []);
  
  return (
    ...
  )
}
```

<h3>🍳 Breakdown 🍳</h3>

Not so much of a breakdown, but as you can see: 
Cool thing about `useEffect` is that you can write functions for both mounting and unmounting in the same place. 

`componentWillUnmount` is useful when doing cleanups as mentioned above, without that, it can cause severe memory leaks on a bigger project. 

---

<h2>Conclusion</h2>

As this article is getting longer, I promise I will keep this conclusion section short but short enough to give you room to think about. 

React Hooks are taking over in modern React, as it is created to be more relevant and timeless (according to the React doc). 

From the comparisons above, we can see how functional components are written shorter and simpler, which makes it easier to read, write and test -- because they are just plain JS functions. However, the rendering time and performance in either components do not make a lot of differences. 

I do not necessarily think one is better than the other. A functional programmer may find easier to use functional components, while that applies the same to an object oriented programmer may find easier to use class components. 

As I mentioned in the introduction, I started with class components and I am currently in the transition of using functional components, as I like React Hooks a lot and I feel like I can do a lot more with it, but I still feel more comfortable to use the lifecycle methods in class component. 

There are a lot of discussions out there which one is better than which and why one prefer over the other. Let me know what you think and let's start a discussion down below!

---

<h2>Further Readings</h2>
1. [Container vs Presentational Components in React](https://medium.com/@yassimortensen/container-vs-presentational-components-in-react-8eea956e1cea)
2. [Functional Components Vs. Class Components In React.Js](https://flatlogic.com/blog/functional-components-vs-class-components-in-react-js/)
<br/>👉🏻 They got more in-depth with the analysis and did some performance test
3. [Understanding Functional Components vs. Class Components in React](https://www.twilio.com/blog/react-choose-functional-components) 
<br/>👉🏻 Codepen examples 
4. [Introducing Hooks](https://reactjs.org/docs/hooks-intro.html) (React Documentation) 
<br/>👉🏻 As you may have noticed, I have quoted from React documentation so many times in this article. I promise you you will find the documentation super helpful and also since React is a front-end framework, let's all agree that the design of the documentation makes it more fun to read 🙌🏻
5. [React Class Components vs Functional Components with Hooks: A Never Ending Story](https://andrejgajdos.com/react-class-components-vs-functional-components-with-hooks/) by my developer friend, Andrej. As there are discussions around using Hooks or not, Andrej talked about the pros and cons about React Hooks and why it is better with Hooks. Go check it out if you are interested!

**If you are looking for more articles/resources to read, I recommend to look for articles that are written after Feb 2019, as it is more relevant to the current React version.**