Why React hooks (Part II: Reusable code)
Tags: react, beginners, tutorial, codenewbie
Published: 2019-09-02 06:47:38


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

This article is intended to give you an understanding of how **React Hooks** helps us to share **common logic** between components and **what differences** between using Hooks and other methods. 

> Take a look if you have not read [the Part I](https://dev.to/dinhhuyams/why-react-hooks-part-i-1jo)

You spent 2 hours writing a beautiful functionality in your component and then just a minute later, your Boss wants **the same thing**  ... but in another component. What should you do now?

> 😅 Easy, I will do some copy + paste stuff

![Copy-paste](https://user-images.githubusercontent.com/26871154/64095209-da0aa600-cd66-11e9-85f9-8cea2dcf7d9b.jpg "Copy paste")

As a React developer, you will at some point run into the situation where you have to **share some common logic** between components. **Higher-order components (HOCs)** are well known in the React community for solving that kind of issue. However, I found **HOCs** a little bit complicated for beginners to get the idea while Hooks makes it way much easier and cleaner. 

## 💪 Let's get started!

‍Our task today is to help **Carey** to teach her naughty twins, [Zack and Cody ](https://www.imdb.com/title/tt0426371/), she will shout at them if they do something bad many times

• Zack.jsx

```jsx 
class Zack extends React.Component {

    state = {
        numberOfBadActions: 0
    }
    
    componentDidUpdate(prevProps, prevState) {
       if (
        prevState.numberOfBadActions !== this.state.numberOfBadActions && 
        this.state.numberOfBadActions === 3
       ) {
        console.log('Use your head!')
        this.setState({numberOfBadActions: 0})
       }
    }
    
    doBadAction = () => {
        this.setState(state => ({numberOfBadActions: state.numberOfBadActions + 1}))
    }

    render() {
        return (
            <div>
                <p>Number of bad actions: {this.state.numberOfBadActions}</p>
                <button onClick={this.doBadAction}>Do bad action</button>
            </div>
        )
    }
}

export default Zack
``` 

Look at Cody, I have to shout at him, too! 😫

## 0. Copy + paste

I've just copied **Zack.jsx** and rename the file to **Cody.jsx** and also change the component name to Cody

• Cody.jsx

```jsx 
class Cody extends React.Component {

    state = {
        numberOfBadActions: 0
    }
    
    componentDidUpdate(prevProps, prevState) {
       if (
        prevState.numberOfBadActions !== this.state.numberOfBadActions && 
        this.state.numberOfBadActions === 3
       ) {
        console.log('Use your head!')
        this.setState({numberOfBadActions: 0})
       }
    }
    
    doBadAction = () => {
        this.setState(state => ({numberOfBadActions: state.numberOfBadActions + 1}))
    }

    render() {
        return (
            <div>
                <p>Number of bad actions: {this.state.numberOfBadActions}</p>
                <button onClick={this.doBadAction}>Do bad action</button>
            </div>
        )
    }
}

export default Cody
``` 

> I feel like patting myself on the back for solving this in just 1 second 😎

It looks good for now until later **Carey** decides to change the method of teaching her sons. In that case, we end up updating **2 components** at the same time and could you imagine what if she has to do the same thing with her sons' friends, too. That's tricky because we have to copy and paste the code everywhere and the hard part is that we have to update all these components if something related to that logic needs to be changed 😖

## 1. Higher-Order Component

> A higher-order component is a function that takes a component and returns a new component

In our case, all you need to do is to take all the teaching-related things outside the React component and move it into a HOC

```jsx 
export const withMom = (WrappedComponent) => {
    return class WithMom extends React.Component {
         state = {
             numberOfBadActions: 0
         }
         
         componentDidUpdate(prevProps, prevState) {
            if (
              prevState.numberOfBadActions !== this.state.numberOfBadActions && 
              this.state.numberOfBadActions === 3
            ) {
              console.log('Use your head!')
              this.setState({numberOfBadActions: 0})
            }
         }
         
         doBadAction = () => {
            this.setState(state => ({numberOfBadActions: state.numberOfBadActions + 1}))
         }
         
         render() {
            return (
                <WrappedComponent 
                    numberOfBadActions={this.state.numberOfBadActions} 
                    doBadAction={this.doBadAction}
                    {...this.props}/>
                )   
         }   
    }
}
``` 

**withMom HOC** is a function that accepts one argument as Component and returns a new and enhanced Component with all logics related to teaching. Now you can use **withMom HOC** to wrap components like below 👇:

• Zack.jsx

```jsx 
class Zack extends React.Component {
    render() {
        return (
            <div>
                <p>Number of bad actions: {this.props.numberOfBadActions}</p>
                <button onClick={this.props.doBadAction}>Do bad action</button>
            </div>
        )
    }
}

export default withMom(Zack)
``` 
• Cody.jsx

```jsx 
class Cody extends React.Component {
    render() {
        return (
            <div>
                <p>Number of bad actions: {this.props.numberOfBadActions}</p>
                <button onClick={this.props.doBadAction}>Do bad action</button>
            </div>
        )
    }
}

export default withMom(Cody)
``` 

**HOC** helps you to organize your code in a much better way. In our case, **Zack and Cody** components do not care about the teaching logic anymore because now the **withMom HOC** encapsulates that logic and passes it down to the wrapped component. And the amazing part is that if **Carey** wants to change her method, all we need to do is to tweak the code in only **1 place** - withMom HOC.

😓 Unfortunately, there is a major downside to using HOCs. Imagine that you have more than one HOC to consume then you start to face up with the problem of controlling all the passing down props and [Wrapper Hell](https://i.redd.it/pdvkpgjq6vo11.jpg) issue

```jsx 
export default withGrandPa( 
    withDad(
        withMom(
            Cody
        )
    )
)
``` 

Then our DOM looks like this

```jsx 
<WithGrandPa>
    <WithDad>
        <WithMom>
            <Cody/>
        </WithMom>
    </WithDad>
</WithGrandPa>
``` 

> **Normal people:** Wrapper Hell

> **Me as an intellectual:** My Asian family clean architecture 👪

<img src="https://user-images.githubusercontent.com/26871154/64095235-ed1d7600-cd66-11e9-93d6-1d84f209ccca.png" width="600" title="Asian family"/>

## 2. React Hooks

🔥 It would be a long story here, stay with me and I will walk you through step by step. 

> If you have not read [the Part I](https://dev.to/dinhhuyams/why-react-hooks-part-i-1jo) of this series, I recommend you read it first then come back otherwise you may get lost

• **Step 1:** Convert the Zack component to a function component

```jsx 
const Zack = () =>  {
    
    const [numberOfBadActions, setNumberOfBadActions] = React.useState(0)
    
    React.useEffect(() => {
        if (numberOfBadActions === 3) {
            console.log('Use your head!')
            setNumberOfBadActions(0)
        }
    }, [numberOfBadActions])
    
    const doBadAction = () => {
        setNumberOfBadActions(numberOfBadActions => numberOfBadActions + 1)
    }

    return (
      <div>
        <p>Number of bad actions: {numberOfBadActions}</p>
        <button onClick={doBadAction}>Do bad action</button>
      </div>               
    )
}

export default Zack
``` 

• **Step 2:** Write custom Hook  

> A custom Hook is a JavaScript function whose name starts with ”use” and that may call other Hooks.

```jsx 

const useYourHead = (initialNumberOfBadActions) => {
    const [numberOfBadActions, setNumberOfBadActions] = React.useState(initialNumberOfBadActions)
    
    React.useEffect(() => {
        if (numberOfBadActions === 3) {
            console.log('Use your head!')
            setNumberOfBadActions(0)
        }
    }, [numberOfBadActions])
    
    const doBadAction = () => {
        setNumberOfBadActions(numberOfBadActions => numberOfBadActions + 1)
    }
    
    return [numberOfBadActions, doBadAction]
}
``` 

When we need to share logic between 2 functions, we extract the logic to a third function. The same thing is applied when we want to share logic between React components because they are functions and Hook is also **a function**. 

I've just extracted all the code that we want to share to a **custom Hook** named `useYourHead`. We need to think about what arguments this function should accept and what it should return as **custom Hook** is just a normal function. In our case, `useYourHead` accepts the initial number of bad actions and return `numberOfBadActions` as well as `doBadAction`

• **Step 3:** Use our custom Hook

```jsx  
const Zack = () =>  {
    
    const [numberOfBadActions, doBadAction] = useYourHead(0)

    return (
        <div>
            <p>Number of bad actions: {numberOfBadActions}</p>
            <button onClick={doBadAction}>Do bad action</button>
        </div>                 
    )
}

export default Zack
``` 

```jsx 
const Cody = () =>  {
    
    const [numberOfBadActions, doBadAction] = useYourHead(0)

    return (
        <div>
            <p>Number of bad actions: {numberOfBadActions}</p>
            <button onClick={doBadAction}>Do bad action</button>
        </div>                 
    )
}

export default Cody
``` 

## 3. Conclusion:
🚀 Hooks help us to inject **reusable logic** to React components without creating HOCs. As you can see, we don't have to deal with the issue of **Wrapper Hell** or the problem of passing down props through many component layers. 👏👏👏

Here are some good resources for you:
- [React HOCs](https://www.robinwieruch.de/gentle-introduction-higher-order-components)
- [Custom Hooks](https://reactjs.org/docs/hooks-custom.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!

*Please leave your comments below to let me know what do you think about this article*

### ✍️ 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)