Let's Talk About Hooks - Part 1 (useState and useEffect)
Tags: react, javascript, beginners, webdev
Published: 2022-05-22 08:59:23

Salam and holla!

Today, I will explain React, specifically the hooks. I will write the hooks in series, so you can take it slowly to understand how hooks work under the hood, and use it appropriately on your code.

Bear in mind, that these writings are of my own, and there might be a better way to use hooks, but my focus will be on understanding how each React hooks work.

And for this one, I will focus on the most basic hooks of all - `useState` and `useEffect`.

Let's start, shall we?

In this article, these are the topics covered:
1. [What Is Hook, By The Way?](#section-1)
2. [`useState` - The Pillar of States](#section-2)
3. [`useEffect` - The Lifecycle of Components](#section-3)
4. [The Reusability of Hooks](#section-4)
5. [Conclusion](#section-end)

---

## What Is Hook, By The Way? <a name="section-1"></a>

In the beningging.... Uhhh, I mean,

In the beginning, React components are created using class components. So, the methods of React components are extended from `Component` object, which contains several setters and getters for states and other stuff like the lifecycle of the component. This is good, but there are some concerns addressed by the React, which are:

- **The Reusability**: When you write functions, and you 
want to use it in other components, you are required to restructure your code to adapt the scalability, especially when you deal with higher-order components.
- **Verbosity**: Using methods in class components can be a hassle, especially when you want to separate different concerns in your component, but class components only allow you to only use the method from `Component` class such as `componentDidMount`, `componentDidUpdate` and others. With those, it is hard to read the code and find the relation between the concerns and only view it from a component lifecycle perspective only.
- **The Nature of OOP**: Object-oriented Programming (OOP) is one of the coding paradigms and is also available in Javascript, however, React found that OOP becomes a barrier for beginners to learn.

You can learn more about [the motivation behind hooks in React](https://reactjs.org/docs/hooks-intro.html#motivation).

With these, the hooks are established, with a condition that we are moving from class components to functional components.

Here's the general difference between class components and functional components.

```jsx
// Class Component

class MyComponent extends React.Component {
  constructor() {
    super();
    this.state = {
      // Your states here
    };
  }

  componentDidMount() {
    // Your lifecycle actions
  }

  render() {
    return (
      <YourJSXHere />
    );
  }
}

------

// Functional Component (Arrow Function)

const MyComponent = () => {
  const [myState, setMyState] = useState();

  useEffect(() => {
    // Your lifecycle actions
  }, []);

  return (
    <YourJSXHere />
  );
};
```

> Disclaimer: This article won't discuss class components vs functional components. Instead, will focus on the usage of hooks, and thus will show only functional components at this point.


---

## `useState` - The Pillar of States <a name="section-2"></a>

Well, I did write about the basics of states and props, and you can take a look at it in my article here:

{% link https://dev.to/alserembani/reactjs-the-basic-of-state-and-props-28a1 %}

And, to also understand a bit about destructuring, you can just read about destructuring below.

{% link https://dev.to/alserembani/javascript-destructuring-the-thing-8ap %}

But, to simplify it, the state is something that changes, so that React can trigger rerender when it happens.

The hook that does the thing is `useState`. Let us take a look at its usage.

```jsx
import { useState } from 'react'; 

const MyComp = () => {
  const [myState, setMyState] = useState();

  // ...
}
```

`useState` is a hook to create the state for you. It returns 2 values, which are the value of the state and the state mutator. You will pass a value inside `useState`, which is the initial value.

Using the example above, `myState` is the state itself, so you can use it in your JSX. When you trigger the mutator, React will trigger the rerender, and then you can see the changes in your render.

> State can be any name you want. `myState` is just an example, so you can use something like `teacher`, `isToggle` or anything that reflects on what changes you want to monitor.

And `setMyState` is the mutator function, for you to change the state. It can be any value, such as string, number, boolean, and even object. Let's see how we can use the mutator function to change the state.

```jsx
const [isActive, setActive] = useState(false);

// This is function to handle click events
const handleToggle = () => {
  setActive((prevState) => {
    return !prevState;
  };
};
```

Okay, it is time to slow down the clock and let's see what we have here.

`setActive` in this example is the mutator function for the state `isActive`. Assuming that the user presses the button to toggle the active state, we call the mutator function to change from `false` to `true`, and vice versa.

So, we pass a function to the `setActive` which returns a new value for the state. For the function, it will accept one parameter, which is the previous state, and then you can do whatever mutations you want, and finally returns the new value to the mutator function.

This is an example of string manipulation.

```jsx
const [myName, setMyName] = useState('');

const updateName = (newName) => {
  setMyName(() => {
    return newName;
  }

  // Can also be shorter
  setMyName(() => newName);

  // Make it shorter!
  setMyName(newName);
};
```

Noticed that I omit the `prevState` thing? Yeah, that is actually optional, and you can make it shorter!

So, that is how you use `useState`. Three things to pay attention to:

- **Initialisation**: You can initialise the value by passing it to `useState`. So it will be `useState(initialValue)`
- **Your state**: You can call the state later to get the value anywhere in your code, as long as it is inside the functional component.
- **The state mutator**: To change state, use mutators. If you try to change state directly without using a mutator, React will just ignore your existence, and just don't pay any attention. Sad life.

---

## `useEffect` - The Lifecycle of Components <a name="section-3"></a>

Before introducing `useEffect`, let us revise what is the lifecycle of components inside React.

![React Lifecycle Methods](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a0upethti4utivzn9kb9.png)

Across render cycles, there are 4 main phases, which are mount, update, error handling and unmount.

The mount phase is the born of the component in the render. When the user opens a page, the mount phase will be triggered.

The update phase is when there is a change in state. Remember that I mentioned rerenders when the state changes? Yes, this is the phase that is responsible for the changes to the render.

The error handling phase is when there is some problem with the lifecycle. For example, somehow there is an error regarding your state, and later React will send a signal (or error) for logging, and will handle the render for you.

And finally, unmount is the end of your component's life, which happens when you close the page or are redirected away from the page.

In class components, there are a lot of methods available for you to use to allow granular control of the lifecycle. Functional components, however, only require one hook to manage it.

Let's get into the usage of `useEffect`, then!

### When Should I use `useEffect`?

When you need to update values that are reflected in the DOM, then you need to use `useEffect` where it will be triggered when its dependencies have changed. Wait, what is a dependency? I will get to it soon. Let's see the anatomy of the `useEffect`.

```jsx
useEffect(yourActionsDuringChanges, [dependencies]);
```

There are two things that you should pass to `useEffect`, which are your function to be triggered during dependency updates, and the array of dependencies.

```jsx
useEffect(() => {
  // Any functions you want during dependency updates
  // componentDidMount, componentDidUpdate, componentDidCatch

  return () => {
    // componentWillUnmount
  }
}, [dependencies]);
```

As you can see above, functions that you put inside `useEffect` will run as soon as React detect changes to any dependency. Comparable to class methods such as `componentDidMount`, `componentDidUpdate` and `componentDidCatch`, but now it can be packed into one `useEffect` function. While the `componentWillUnmount` method is comparable to the function's return, it will run during the component unmounting.

Then, what is a dependency? Well, dependency is the variable that you want `useEffect` to listen for changes. Let's see an example then.

```jsx
const [humanName, setHumanName] = useState("Atif");
const [catName, setCatName] = useState("Armel");

useEffect(() => {
  console.log(`My cat's name is ${catName}`);
  
  return () => {
    console.log(`${humanName} says goodbye.`);
  }
}, [catName]);
```

Using the example above, there are 2 states declared, which are `humanName` and `catName`. And for `useEffect`, I pass a function and one dependency only, that is `catName`. Okay, I have questions for you.

1. When I open the page, what happened?
2. If I update `catName` to "Akamaru", what happened?
3. If I update `humanName` to "Kiba", what happened?
4. When I close the page, what happened?

Well, do you get the answer? Here's the answer.

1. When I open the page, the component will be mounted. For the class component, this is the phase we called `componentDidMount`. So, the console will print out `My cat's name is Armel`.

2. If I update `catName` to "Akamaru", `useEffect` will be triggered, since `catName` is included as a dependency for it. For the class component, this is the phase we called `componentDidUpdate`. So, the console will print out `My cat's name is Akamaru`.

3. If I update `humanName` to "Kiba", `useEffect` won't be triggered, since `humanName` is not one of the dependencies of `useEffect`. Nothing happened.

4. When I close the page, the component will unmount. For the class component, this is the phase we called `componentWillUnmount`, getting ready for a cleanup. The console will print out `Kiba says goodbye`. Remember that in number 3, I've updated `humanName`, that is why the console print out "Kiba" instead of "Atif". `useEffect` won't be triggered by the change of `humanName`, but it will still refer to the current value of the `humanName`.

Can we include more than one dependency? Well, sure you can! If I want to track changes to both `catName` and `humanName`, I can just add it, so `useEffect` will be triggered when any one of the dependency from the array of dependencies changes.

Can we add other than states as dependencies? For your information, you can also include things like props, refs and others as well, as long as the value changes. But be mindful of what you include as dependency, because in some cases, rerenders can be quite expensive.

---

## The Reusability of Hooks <a name="section-4"></a>

Remember when I said that hooks are reusable? Yes, hooks are indeed reusable. Notice in previous example, I used two `useState`s? You can declare as many states you want. Same applied to `useEffect` as well!

```jsx
const [humanName, setHumanName] = useState('Atif');
const [catName, setCatName] = useState('Armel');

useEffect(() => {
  console.log(`I've changed my name to ${humanName}`);
}, [humanName]);

useEffect(() => {
  console.log(`I've changed my cat's name to ${catName}`);
}, [catName]);
```

As you can see, there are 2 `useEffect`, where the first one will be listening to `humanName`, while the latter will be listening to `catName`. With this, you can seperate the concern, while dealing with the same lifecycle phases. Do as much as you want!

"Well, this is interesting. But how about I just want to run it only once, during the mount, or maybe during the page closure?"

Well, I got just the thing for you!

```jsx
useEffect(() => {
  console.log("Just open the page!");
}, []);

useEffect(() => {
  return () => {
    console.log("Will close the page");
  }
}, []);
```

Notice that I didn't include any dependency, but remember that `useEffect` will always trigger during mounting, so the console only prints out once.

For the second one, I just log the console in the return, which means that it will only happen during unmount, so the console only prints when you close the page.

So, there are three ways (actually!) to use `useEffect`.

```jsx
// Runs once during mount
useEffect(() => {
  // Anything
}, []);

// Runs during dependency update
useEffect(() => {
  // Anything
}, [yourDependency]);

// Runs as long as there is rerenders
useEffect(() => {
  // Anything
});
```

For the first and the second, I've already explained how it works, but the third one will run as long as there is rerenders.

> I would recommend you to add an empty array or array of dependencies unless you know what you are doing. Rerenders are already costly, triggering `useEffect` every time will be expensive too.

There is another thing that you need to bear in mind.

```jsx
// Don't do this
const [humanName, setHumanName] = useState('Atif');

useEffect(() => {
  setHumanName(() => 'Ahmad');
}, [humanName]);
```

If you make an attempt to update your state, which happens to be included as your dependency, this will trigger and runs indefinitely, and your computer will enter a phase of "Dormamu, I've come to bargain!" thing. Nope, don't do this!

Same as the following example.

```jsx
// Don't do this
const [humanName, setHumanName] = useState('Atif');
const [catName, setCatName] = useState('Armel');

useEffect(() => {
  setCatName(() => 'Akamaru');
}, [humanName]);

useEffect(() => {
  setHumanName(() => 'Kiba');
}, [catName]);
```

I know, some of you might have weird ideas, but this also triggers an infinite loop! Updating each other's dependency will throw you into the unknown!

---

## Conclusion <a name="section-end"></a>

Well, that's it for `useState` and `useEffect`! These 2 hooks are the basic hooks which can be used in React functional components. If you understand every behaviour of these states, you can already develop your own hooks by just using `useState` and `useEffect`! You can head to [useHooks](https://usehooks.com/) to see them in action on how you can make your own hooks.

Before I close this article, there is a similar hook as `useEffect` we called `useLayoutEffect`. So what is the difference then? There are still a lot of hooks that you can discover, but it will be for other articles.

Any questions, or if you detect some error, please comment down below, and share (if you will) for more understanding of how hook works in React.

Until next time, adios, and may be peace upon ya!