# A Complete Introduction to React Hooks

React hooks are great additions to React which has completely changed how we write code. Hooks were introduced in React starting with version 16.8.0.

Before React hooks, there was no way of using state and lifecycle methods in functional components, and that’s why the functional components were called Stateless Functional Components. 

Now, with the introduction of React hooks, we can use life cycle methods and state in functional components. Using hooks makes our code a lot simpler, shorter, and easy to understand.

## Installation

To start using React hooks, you need to use the latest version of `create-react-app`. 

If you are using your own webpack setup for React as described in [this article](https://javascript.plainenglish.io/webpack-and-babel-setup-with-react-from-scratch-bef0fe2ae3e7?source=friends_link&sk=880a6b9a35fb638eef19e5e99276428e), you need to install the latest version of `react` and `react-dom` using:

```js
npm install react@latest react-dom@latest
```

Let’s start exploring React Hooks now.

> Hooks are the functions that let you “hook into” the React state and lifecycle features in functional components.

React provides many built-in hooks and also allows us to create our own custom hooks.

Let’s look into some of the most important built-in hooks.

## useState Hook

This is the first hook provided by React which allows us to use state inside the functional component.

The `useState` hook accepts a parameter which is the initial value of the state.

In class-based components, state is always an object but when using `useState`, you can provide any value as the initial value like number, string, boolean, object, array, null etc.

The `useState` hook returns an array whose first value is the current value of the state and the second value is the function which we will use to update the state similar to `setState` method.

Let’s take an example of class-based component which uses state and we will convert it into a functional component using hooks.

%[https://gist.github.com/myogeshchavan97/38c0ad6b022082a8ba1fcbcd6ef3f24c]

Here's a [Code Sandbox Demo](https://codesandbox.io/s/delicate-thunder-xdpri).

Let’s convert the above code to use hooks.

%[https://gist.github.com/myogeshchavan97/46ff174c00efa93b51d57252fbfc6964]

Here's a [Code Sandbox Demo](https://codesandbox.io/s/elegant-heyrovsky-3qco5).

Let’s understand the above code
1. To use the `useState` hook, we need to import it as we have done it in the first line.
2. Inside the App component, we are calling `useState` by passing `0` as the initial value and using destructuring syntax, we stored the array values returned by `useState` into `counter` and `setCounter` variables.
3. It’s a common convention to prefix the function name used to update the state with `set` keyword as in `setCounter`.
4. When we click the increment button, we are defining an inline function and calling the `setCounter` function by passing the updated `counter` value.
5. Note that, as we already have the `counter` value, we have used that to increment the counter using `setCounter(counter + 1)`
6. Since there is a single statement in the inline on click handler, there is no need for moving the code into a separate function. Though you can do that if the code inside the handler becomes complex.

We can have multiple `useState` calls in a single functional component:

%[https://gist.github.com/myogeshchavan97/0531ae630a32aeb38d605b97a580d8fb]

Here's a [Code Sandbox Demo](https://codesandbox.io/s/long-framework-n1tyn).

As you can see in the above code, we have declared two `useState` calls and both username and counter are independent of each other.

We can add as many `useState` calls as needed.

### State is not merged when using `useState` hook

One thing to note if you are using `object` in `useState` is that, state is not merged when updating the state.

Let’s see what happens when we combine the `username` and `counter` into an object to update the state.

%[https://gist.github.com/myogeshchavan97/d3781b1109e69c72edd67b6eb5d9f8c6]

Here's a [Code Sandbox Demo](https://codesandbox.io/s/sleepy-darkness-6jz9b).

If you run the code and try to increment the counter, it works but as soon as you try to type into the input field, the counter value vanishes and when you again try to increment the counter, it shows as `NaN` and you will also get a warning in the console.

> This is because using an object in `useState` will completely replace the object instead of merging it when we set the state using `setState` method.

In the above code, initial state value is

```js
{ counter: 0, username: "" }
```

but when we call increment method, it becomes

```js
{ counter: 1 }
```

and so the `username` is lost.

If you type in the input field first, then

```js
{ counter: 0, username: "" }
```

becomes

```js
{ username: "new_value" }
```

and so the `counter` is lost.

> Because of this, it’s recommended to use multiple `useState` calls instead of using a single `useState` to store object.

If you still want to use an object in `useState`, you need to manually merge the previous state like this:

```js
const handleOnClick = () => { 
  setState(prevState => ({
   ...prevState,
   counter: prevState.counter + 1
  }));
};

const handleOnChange = event => {
 const value = event.target.value;
 setState(prevState => ({
   ...prevState,
   username: value
 }));
};
```

Here's a [Code Sandbox Demo](https://codesandbox.io/s/strange-dawn-s0nyi).

## useEffect Hook

React provides a `useEffect` hook using which we can implement lifecycle methods in functional components.

The `useEffect` hook accepts a function as its first parameter and an optional array as the second argument.

`useEffect` lets you perform side effects in a functional component.

> Data fetching, setting up a subscription, and manually changing the DOM in React components are all examples of side effects.

`useEffect` takes two arguments: a function and an optional array.

`useEffect` serves the same purpose as `componentDidMount`, `componentDidUpdate`, and `componentWillUnmount` combined together.

Take a look at the below code:

%[https://gist.github.com/myogeshchavan97/0080f90fc420f90bec13e7e44d22640f]

Here's a [Code Sandbox Demo](https://codesandbox.io/s/stupefied-darwin-qpcmm).

If you run the code, you will see that function provided in `useEffect` is invoked immediately on page load i.e when the component is mounted. It will also be called when the component is re-rendered when any state or prop changes.

So when you click the increment button, the `useEffect` hook will be called again.

So it serves the purpose of `componentDidMount` and `componentDidUpdate` lifecycle methods.

If you want the effect to be called only when the component is mounted, you need to provide an empty array as the second argument to `useEffect` call.

```js
useEffect(() => {
  console.log("useEffect called");
}, []);
```

So now, this effect will be called only when the component is mounted and never again.

Here's a [Code Sandbox Demo](https://codesandbox.io/s/gifted-newton-71vzl).

Take a look at the below code:

%[https://gist.github.com/myogeshchavan97/70dcfc4e2e6de50583e71e88ce10e8b8]

Here's a [Code Sandbox Demo](https://codesandbox.io/s/long-framework-n1tyn).

As you can see, the `useEffect` gets executed when the counter is changed and also when the username is changed.

If you want that to be executed only when the counter is changed, you need to mention that in the dependencies array which is the second argument to `useEffect`.

```js
useEffect(() => {
 console.log("This will be executed when only counter is changed");
}, [counter]);
```

This is very important to understand because if you are doing some computation in `useEffect` when the counter is changed, there is no point in executing that code when the username or any other prop or state is changed.

> So by providing the variable in the dependencies array, the effect will be executed only when those dependencies are changed.

This is a great improvement because it will remove the need for the extra condition we used to have in the `componentDidUpdate` method

```js
componentDidUpdate(prevProps) {
 if(prevProps.counter !== this.props.counter) {
  // do something
 }
}
```

So using `useEffect` and mentioning dependencies removes the need of comparing previous props or state value with the current prop or state value because the code inside `useEffect` will only be executed when the dependencies change.

If you have multiple dependencies, you can specify that as a comma-separated value in the dependencies array.

```js
useEffect(() => {
 console.log("This will be executed when any of the dependency is changed");
}, [counter, some_other_value]);
```

### Cleaning up the effect

If you return a function from the `useEffect`, it will be called before the component will be unmounted. So it’s similar to `componentWillUnmount` method.

Let’s say you are using the `setInterval` function, then you can clear the interval in the function returned by `useEffect`.

> This cleanup effect runs when the component unmounts as well as before re-running the `useEffect` due to a subsequent render.

%[https://gist.github.com/myogeshchavan97/0ea32762f69a0d81ad5282c024baba72]

Here's a [Code Sandbox Demo](https://codesandbox.io/s/sleepy-wood-biu89).

In the above code, we have added a scroll event handler which will be registered only once, when the component is mounted because we have passed an empty array `[]` in `useEffect` dependencies list.

*This code displays a message in the console when the page is scrolled.*

When we click on the `unmount component` button, the component will be removed and the function returned from the `useEffect` will be called where we remove the scroll event handler and print the message `component unmounted` to the console.

It is important to note that in the child component, `useEffect` will be called for every re-render of the parent component.

Take a look at the below code:

%[https://gist.github.com/myogeshchavan97/aff9cc01da65d648c2e3cee0655222c1]

Here's a complete [Code Sandbox demo](https://codesandbox.io/s/jolly-tesla-gj170).

Here, we are adding a new todo. So for every added todo, the TodoList component will be re-rendered and so the `useEffect` defined in the TodoList will be called for every re-render printing the message in the console.

So if you don’t want to re-render the effect of TodoList, you need to pass an empty array `[]` as the dependency in the `useEffect` second argument.

```js
useEffect(() => {
 console.log("This will be executed only once");
}, []);
```

### Multiple useEffect in a single component

You can also have multiple `useEffect` calls in a single functional component, each doing different tasks, and React will call them in the order they are defined in the component.

## useRef Hook

The `useRef` hook allows us to get access to any DOM element which is the same as working with ref in React.

It has the following syntax:

```js
const refContainer = useRef(initialValue);
```

The `initialValue` is optional.

%[https://gist.github.com/myogeshchavan97/cb2cb479e27629c71259126a5d96b3b3]

Here's a [Code Sandbox Demo](https://codesandbox.io/s/damp-water-fye8r).

As you can see we have created the reference using:

```js
const usernameRef = useRef();
```

and assigned it to the input field. So now we can access the input field by using `usernameRef.current` property anytime we want to get access to the input field.

`useRef` is not exactly the same as React ref because `useRef` returns a mutable ref object whose current property is initialized to the passed argument (`initialValue`).

> The returned object will persist for the full lifetime of the component.

%[https://gist.github.com/myogeshchavan97/29b83d08c9f65352810ad1dae16c3a8e]

Here's a [Code Sandbox Demo](https://codesandbox.io/s/black-cache-e5vlb).

In the above code, we have created a timer that displays the updated time after every second. When we click the unmount component button, then we are clearing the `setInterval` thereby stopping the timer.

Also, note that we have added another `useEffect` call which clears the timer after 5 seconds are passed.

The key point to remember is that we are able to access the same value of the interval variable in the first `useEffect`, even when it’s assigned in the second `useEffect`. 

If we didn’t use `useRef` but used the normal variable, it will not be available in the first `useEffect` because `useEffect` creates a new function for every execution of the effect.

## useReducer Hook

React provides a `useReducer` hook which allows us to use redux for handling complex calculations without the need of installing the redux library.

So it helps to avoid the creation of boilerplate redux action, reducer code.

`useReducer` is usually preferable to `useState` when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one.

The `useReducer` has the following syntax:

```js
const [state, dispatch] = useReducer(reducer, initialState);
```

The `useReducer` accepts `reducer` and `initialState` and returns the `current state` and a `dispatch` function which we can use to dispatch the actions.

Let’s understand through an example. We will create a todo list component that will allow us to add and remove a todo.

Let’s create a `reducer` to handle the todo.

```js
const todosReducer = (state, action) => {
 switch (action.type) {
  case "ADD_TODO":
   return [...state, action.todo];
  case "REMOVE_TODO":
   return state.filter(todo => todo !== action.todo);
  default:
   return state;
 }
};
```

We initialize the initial state of `todosReducer` in `initialState` of `useReducer` as:

```js
const initialState = [];
const [state, dispatch] = useReducer(todosReducer, initialState);
```

and dispatch the actions like

```js
dispatch({ type: "ADD_TODO", todo: value });
```

Here's a [Code Sandbox Demo](https://codesandbox.io/s/admiring-bose-jw6wx).

As you can see, the `useReducer` hook makes it very easy to manage the redux state without actually using redux which is a great improvement.

But this does not mean redux is useless now. If you are managing the larger state or have multiple reducers, you should use redux to handle that.

`useReducer` just make it easy if you want to handle complex states in a single component.

## Creating Custom Hooks

React allows us to create our own custom hooks using the built-in hooks. This allows us to extract component logic into reusable functions.

Let’s take the previous timer code from [here](https://codesandbox.io/s/black-cache-e5vlb) and we will convert it into a custom reusable hook.

%[https://gist.github.com/myogeshchavan97/dc32f7d80d59b10d0b90370ccc825248]

Here's a [Code Sandbox Demo](https://codesandbox.io/s/infallible-visvesvaraya-qkwdw).

Here, we have encapsulated the code for displaying a timer in the `useTimer` function and from that function we are returning the updated time.

So now any component that wants to display the time, can call the `useTimer` function and use this timer hook.

> It’s a common convention to begin the custom hook name with `use` keyword like `useTimer`.

### Things to keep in mind when working with Hooks

* Only call Hooks at the top level. Don’t call Hooks inside loops, conditions, or nested functions. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple `useState` and `useEffect` calls.

* Only call Hooks from React function components. Don’t call Hooks from regular JavaScript functions. But you can call it from your own custom Hooks.

**To learn how to handle API calls using Async/await with the `useEffect` hook check out [this article](https://blog.yogeshchavan.dev/handle-api-calls-using-async-await-inside-the-useeffect-hook-in-react).**

### Thanks for reading!

Want to learn all ES6+ features in detail including let and const, promises, various promise methods, array and object destructuring, arrow functions, async/await, import and export and a whole lot more from scratch?

Check out my [Mastering Modern JavaScript](https://modernjavascript.yogeshchavan.dev/) book. This book covers all the pre-requisites for learning React and helps you to become better at JavaScript and React.

**Check out free preview contents of the book [here](https://www.freecodecamp.org/news/learn-modern-javascript/).**

Also, you can check out my **free** [Introduction to React Router](https://yogeshchavan.podia.com/react-router-introduction) course to learn React Router from scratch.

Want to stay up to date with regular content regarding JavaScript, React, Node.js? [Follow me on LinkedIn](https://www.linkedin.com/in/yogesh-chavan97/).

[<img src="https://gist.github.com/myogeshchavan97/98ae4f4ead57fde8d47fcf7641220b72/raw/c3e4265df4396d639a7938a83bffd570130483b1/banner.jpg">](https://bit.ly/3w0DGum)

[<img src="https://cdn.buymeacoffee.com/buttons/default-yellow.png" >](https://www.buymeacoffee.com/myogeshchavan97)


