A Guide to Hooks in Terms of Classes
Tags: react, hooks, reacthooks
Published: 2019-05-01 01:24:26

---
title: A Guide to Hooks in Terms of Classes
published: true
description: A Guide to using React Hooks written in comparison to the previous implementations using classes. This will hopefully make understanding how to use these new additions to React a bit easier for someone who has already taken the time to learn about React State and Lifecycle with Classes.
tags: react, hooks, reacthooks
---

With the introduction of Hooks, it seems that the React team is trying to push developers away from using Class Components that implement state and lifecycle. Understanding how to use these new features may prove to be a little bit challenging to someone who is so used to Class Components. Hopefully this guide will help bridge the gap between how hooks are used to replace classes.

For this I will just be going over the basic hooks: [useState](https://reactjs.org/docs/hooks-reference.html#usestate) and [useEffect](https://reactjs.org/docs/hooks-reference.html#useeffect).

## useState
So, let's start with the easier of the two. The useState hook replaces, well, state. Pretty obvious there. The only kicker is how it allows us to interact with state. Previously, our state was a class variable of our component.
```javascript
class MyComponent extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = { count: 0 }
  }
}
```
Which could then simple be accessed with `this.state` and mutated with React's `this.setState()` method.
```javascript
class MyComponent extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = { count: 0 }
  }

  render() {
    const { count } = this.state;

    return (
      <button type="button" onClick={() => this.setState({ count: count + 1})}>
        Add One
      </button>
    )
  }
}
```


With hooks, instead of our state being a single object that is accessed with a single method, each piece of state appears to us as individual components.
```javascript
const MyComponent = () => {
  const [count, setCount] = React.useState(0);
  const [myName, setMyName] = React.useState('Andrew');
}
```
The value that is passed to useState is the value state will be initialized with, and, as you could probably guess, `setCount(count + 1)` would increment my count state variable by 1 and trigger an update of MyComponent.

The cool part with the use of hook's state is how it can interact with the useEffect hook.

## useEffect
The useEffect hook has a little bit more to it than useState. Remember those awesome lifecycle methods we used to use?
```javascript
class MyComponent extends React.PureComponent {
  constructor(props) {
    this.state = { channelId: 12345, message: '' }
  }

  this.componentDidMount() {
    discordClient.login(token);
  }

  this.componentDidUpdate() {
    { channelId, message } = this.state;
    discordClient.channels.get(channelId).send(message);
  }

  this.componentWillUnmount() {
    discordClient.destroy();
  }
}
```

```javascript
const MyComponent = () => {
  const isInitialMount = React.useRef(true);
  const [channelId, setChannelId] = React.useState(12345);
  const [message, setMessage] = React.useState('');

  React.useEffect(() => {
    discordClient.login(token);

    return function cleanup() {
      discordClient.destroy();
    }
  }, []);

  React.useEffect(() => {
    if (isInitialMount.current) {
      isInitialMount.current = false;
      discordClient.login(token);
    } else {
      discordClient.channels.get(channelId).send(message);
    }

    return function cleanup() {
      discordClient.destroy();
    };
  }, [message]);

  this.componentDidUpdate() {
    { channelId, message } = this.state;
    discordClient.channels.get(channelId).send(message);
  }
}
```

Now, let's mash them all into a single function `useEffect()`. By default this acts as componentDidMount and componentDidUpdate. So, something like this would run on mount and each time the component updates.
```javascript
const MyComponent = () => {
  React.useEffect(() => {
    console.log('yeehaw');
  });
}
```
If you want something to run on willUnmount, simple return a function from your useEffect like so...
```javascript
const MyComponent = () => {
  React.useEffect(() => {
    console.log('yeehaw');
    
    return function unmount() {
      console.log('componentWillUnmount');
    };
  });
}
```
Whenever the component will unmount from the dom, React will execute the code in the function returned by useEffect. Easy enough, right?

Here comes the cool part, you know how in redux you can subscribe to certain elements of your store. Well, with useEffects you can do the same thing with your state.

Let's say we have a couple state variables, but we only want this effect to happen when one of them updates. Easy peasy.
```javascript
const MyComponent = () => {
  const [howdy, setHowdy] = React.useState('partner');
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    console.log('yeehaw');
  }, [count]);
}
```
This useEffect will now only run whenever the value of count changes.

Say you want a useEffect to only run on mount, just pass it an empty Array as the condition.
```javascript
const MyComponent = () => {
  const [howdy, setHowdy] = React.useState('partner');
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    console.log('yeehaw');
  }, []);
}
```

Now, lets try to re-implement that mock discord bot with a useEffect. We want the client to login on mount, send a message when the message updates, and the destroy the client on willUnmount. In order to make the client login only on mount, we'll have to utilize a useRef to determine if it's the initial mount. [This is the suggested implementation by the React team.](https://reactjs.org/docs/hooks-faq.html#can-i-run-an-effect-only-on-updates)
```javascript
const MyComponent = () => {
  const isInitialMount = React.useRef(true);
  const [channelId, setChannelId] = React.useState(12345);
  const [message, setMessage] = React.useState('yeehaw!');

  React.useEffect(() => {
    if (isInitialMount.current) {
      isInitialMount.current = false;
      discordClient.login(token);
    } else {
      discordClient.channels.get(channelId).send(message);
    }

    return function cleanup() {
      discordClient.destroy();
    };
  }, [message]);
}
```

Now get to hookin'!

![Patrick Star playing Hooky](https://media.giphy.com/media/l1AsOnR2Pjuw4tx4I/giphy.gif)