Why React Hooks (Part I: Complicated lifecycles)
Tags: react, beginners, tutorial, codenewbie
Published: 2019-08-25 14:26:34


**Prerequisite:** Basic knowledge about [React](https://reactjs.org/)

In this post, we are going to talk about **one** in million reasons why we should all start to learn and use Hooks even though fishing is not our hobby 🐟 🎣. 

> Hey Siri, set timer for 5 minutes 😋

If you have never tried Hooks or heard of it before, stay with me for **5 mins** and you can immediately recognize the first important benefit of Hooks 🥇. 

I have started to use React hooks for about a month and it is a real game-changer. One clear benefit of Hooks is that it helps us remove redundant **complicated React lifecycles**.

> Didn’t you see the no-fishing sign, son?

> Me: I’m not fishing, sir. ....

😎 Let's how it works in action

Our task today is simply to subscribe the user to a radio channel 📻.

## 1. Class component

For this simple task, we will use the **componentDidMount** lifecycle

```jsx
class Radio extends React.Component {
    state = {channelId: 1}
    
    componentDidMount() {
        subscribeToRadio(this.state.channelId)
    }
    
    ...
}
```

One channel is kind of boring 🙃

Let's allow users to jump to their favorite channels by clicking the button. For this, we need to unsubscribe from the previous channel before subscribing to the new one, **componentDidUpdate** should be the right place to do this

```jsx
class Radio extends React.Component {
    
    ...
    
    componentDidUpdate(prevProps, prevState) {
        if (prevState.channelId !== this.state.channelId) {
        
            unsubscribeRadio(prevState.channelId)
            
            subscribeToRadio(this.state.channelId)
        }
    }
    
    changeChannel = () => {
        const id = randomId()
        this.state({channelId: id})
    }
    
    render() {
    
        return (
                <div>
                    <p>Current channel: ${channelId}</p>
                    <button onClick={this.changeChannel}>Change channel</button>
                </div>
            )
    }
}
```

Last but not least, we have to unsubscribe to the channel when the user stops listening. We will do this in **componentWillUnmount**

```jsx
class Radio extends React.Component {
    
    ...
    
    componentWillUnmount() {
        unsubscribeRadio(this.state.channelId)
    }
}
```

So, for this dead simple radio subscribing task, we still need **3 lifecycles** in total:

- componentDidMount
- componentDidUpdate
- componentWillUpdate 

If you add more and more features, I assume it has some side-effects, to your app, these features would be grouped by lifecycle methods instead of by side-effect. You will end up stacking up logics all across these lifecycle methods.

🤨 🧐 😕

Imagining when you have a bug 🐛, you need to go through **3 different places** to find and fix it. You have to play [Three-bug Monte](https://en.wikipedia.org/wiki/Three-card_Monte) game to 
find that bug and I bet you all know how difficult it is to win that kind of game 🤦‍


![bugs](https://user-images.githubusercontent.com/26871154/63650946-ec7a5380-c758-11e9-854b-41f8ac27526a.jpg "Bugs")

## 2. Function component with Hooks

🔥 Hooks come to rescue

> Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class.

Let's see how Hook does to achieve the same result. To use Hooks, we need to convert the class component above to a functional component. We can create a super simple component in the following way: 

```jsx
const Radio = () => {
    const [channelId, setChannelId] = React.useState(1)
    
    React.useEffect(() => {
        subscribeToRadio(channelId)
        
        return () => unsubscribeRadio(channelId) 
    }, [channelId])
    
    const changeChannel = () => {
           const id = randomId()
           setChannelId(id)
    }
    
    return (
        <div>
            <p>Current channel: ${channelId}</p>
            <button onClick={changeChannel}>Change channel</button>
        </div>
    )
    
}
```

> 😲 Wow, It's magic. How do you do that?

**React.useState** and **React.useEffect** are React Hooks that helps you achieve the same results as you did with lifecycles. Even though you might not totally clear on those above Hooks, I bet the function names might give you some hints, and you can still immediately feel that Hooks make the code much cleaner and simpler.

As you can see, all the logics are concentrated in **1 Hook** instead of **3 places** like before. It is easier to debug. If you want to remove the feature, all you need is to delete the related effect.

💪 Let's break it down, together.

### • useState

> **useState** is a Hook that helps us manage local state in function component.


```jsx
const Radio = () => {
    const [channelId, setChannelId] = React.useState(1)
    
    const changeChannel = () => {
        const id = randomId()
        setChannelId(id)
    }
    
    ...
}
```

The **useState** Hook accepts **initial state** as its argument. In the code above, `1` is the initial value for **channelId**. 

This Hook returns an array which contains 2 variables where the first one is the **current state** and the second one is a function that allows us to **update state**. We are using array destructuring `[channelId, setChannelId]` and you can name them whatever you want

### • useEffect

**React.useEffect** lets us perform side effects in function component

```jsx
const Radio = () => {

    const [channelId, setChannelId] = React.useState(1)
        
    React.useEffect(() => {
        subscribeToRadio(channelId)
    }) 
    
    ...   
}
```

In this effect, we perform the radio channel subscription. By default, our effect will run after every component's rendering and updating.

However, that's actually not what we want, if we only need to perform this effect only once after the first render (**componentDidMount**), we need to pass an empty array as a second optional argument of useEffect Hook. An empty array means that this effect depends on nothing, so it will only run on the mount (and unmount if you return a clean-up function)

```jsx
const Radio = () => {

    const [channelId, setChannelId] = React.useState(1)
        
    React.useEffect(() => {
        subscribeToRadio(channelId)
    }, []) 
    
    ...   
}
```

Additionally, we also need to perform the effect after every time the **channelId** state changes (when the user clicks the button). We will tell the effect to do that by passing **channelId** to the array. Remember what you put here in the array is what the effect will depend on. The good news is, you can put multiple variables to this array!!

```jsx
const Radio = () => {

    const [channelId, setChannelId] = React.useState(1)
        
    React.useEffect(() => {
        subscribeToRadio(channelId)
    }, [channelId]) 
    
    ...   
}
```

The effect will determine when **channelId** changes by comparing the **current channelId** value with the **previous channelId** value **(using shallow comparison ===)**.

If those values are unchanged, React would skip the effect 😙. It's the same when we use **componentDidUpdate** lifecycle to compare
**this.state.channelId** and **prev.state.channelId** 

> Note: It uses SHALLOW equality instead of deep comparison

Lastly, we will unsubscribe to 📻 when user changes the channel

```jsx
const Radio = () => {

    const [channelId, setChannelId] = React.useState(1)
        
    React.useEffect(() => {
        subscribeToRadio(channelId)
        
        return () => unsubscribeRadio(channelId) 
        
    }, [channelId]) 
    
    ...   
}
```

The effect returns a function known as the clean-up function.

When using class component, we have to split this logic to 2 components **componentDidUpdate** and **componentWillUnmount**

Our effect will not only run when first render but also every update (when channelId changes), therefore, the clean-up function will be called
each time before the next render

## 3. Conclusion:
One benefit of Hooks is that it makes your [React app 90% cleaner](https://www.youtube.com/watch?v=dpw9EHDh2bM) by removing the complicated lifecycles.

It helps us keep things together, group our app features by side-effect rather than spread them into different lifecycle methods

Feel the need for learning Hooks now, here are some good resources for you:
- [Hooks Intro](https://reactjs.org/docs/hooks-intro.html)
- [Modern React workshop by Kent C. Dodds (Part I)](https://www.youtube.com/watch?v=xcZXS_VEJS0)
- [Modern React workshop by Kent C. Dodds (Part II)](https://www.youtube.com/watch?v=NKAfuguroRY)

## 🙏 💪 Thanks for reading! Brace yourself, part II is coming 

*Please leave your comments below to let me know what do you think about React Hooks*

### ✍️ Written by

**Huy Trinh** 🔥 🎩 ♥️ ♠️ ♦️ ♣️ 🤓

Software developer | Magic lover

Say Hello 👋 on

✅ [Github](https://github.com/HuyAms)

✅ [LinkedIn](https://www.linkedin.com/in/huy-trinh-dinh-253534131/)

✅ [Medium](https://medium.com/@trnhnhhuy)