React Hooks Part 1
Tags: react, webdev, javascript
Published: 2021-01-01 19:13:31

![To-do.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1608748528130/md_iqLdRX.png)

*Originally I have submitted this tutorial to Facebook Community Challenge 2020, you can access and read it from [this link](https://hulyak.github.io/react-tutorial/).*


React is a Javascript library for building user interfaces. You may have worked with class components, and didn't understand why developers are using hooks. As a beginner, it's hard to know which one to use, for example, there are legacy codes written in class components, and you need to refactor it to functional components using Hooks, or you just want to learn the new React, and don't want to invest time learning class components. If you are thinking like this, you are in the right place. This tutorial will show you the details about using `useState` and `useEffect` hooks, as you progress you can go on with different hooks, and libraries. React is a huge library and you will be shocked that there are so many different things that you can do with React only. So, fasten your seatbelts, and enjoy the ride.


### What we will cover 

Throughout this tutorial, we’ll learn how to set state using the `useState` and `useEffect` Hooks. We’ll create different components and for the last component, we will combine these two hooks and create a recipe app that will fetch new recipes from an API. More specifically, we will learn how to: 

- use `useState` with an array/object for the default value
- use `useEffect` without a Dependency Array, with an Empty Dependency Array, with a Non-empty Dependency Array, and with a cleanup function
- fetch an API with `useEffect`

**By the end of the tutorial, you will have the following skill sets:**

- The hands-on practical and real-life scenario of basic React Application using React Hooks.
- You will manage state in a functional component using Hooks, and you’ll have a foundation for more advanced Hooks such as `useCallback`, `useMemo`, and `useContext`.

Here is the live demo of the end result.

[View Demo](https://react-tut-beginner.netlify.app/)

#### Prerequisites

- Basic familiarity with HTML & CSS.
- Basic knowledge of JavaScript ES6.
- Basic understanding of the DOM.
- Basic React knowledge like props, components, one way-data-flow
  
## What Are React Hooks?

Hooks are a new addition in React 16.8. With the help of hooks, we can use state and other React features without writing a class.
Hooks allow for attaching reusable logic to an existing component and use state and lifecycle methods inside a React functional component.
We can organize the logic inside a component into `reusable isolated units`, and we have a `better separation of concerns.`
React Hooks makes developing apps easier with less complexity. It improves the readability and organization of components.
We can create custom hooks to reuse code across our app.

I want to start our tutorial with a general overview of our hooks. This will you a big picture of hooks, then we will dig deeper into our two commonly used hooks. You can just skim over these and use them as a reference when you need them. This may be overwhelming, but no need to worry about it right now. 

![diagram.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1608748552997/YR7PbkfEA.png)

- `useState` is the most common hook that you will see. It is the `state hook` for declaring the state in our components.
- `useEffect` is used for _side effects_ like fetching data from an API.
- `useRef` is used to allow access directly to an element in the DOM and to create a mutable ref object that won't trigger a rerender.
- `useContext` allows us to easily work with the React Context API (solving the prop drilling issue).
- `useReducer` is an advanced version of `useState` for managing complex state logic. It’s quite similar to Redux.
- `useMemo` returns a value from a memoized function.
- `useCallback` returns a function that returns a cacheable value. Useful for performance optimization if you want to prevent unnecessary re-renders when the input hasn’t changed.
- `useLayoutEffect` similar to `useEffect`, they differ in when they trigger.
- `useImperativeHandle` to customize the instance value that’s exposed to parent components when using `ref`.
- `useDebugValue` displays a label for custom Hooks in React Developer Tools.

In this tutorial, we will focus on the most common hooks: `useState` and `useEffect`. But first, let's start with _why we need hooks in the first place._

## Why Hooks?
 
Before Hooks:

- We would need to understand how **this** keyword works in Javascript and to remember to bind event handlers in `class components`.
- A common way to attach logic externally to a component was to use the `render props` or `Higher-Order Components` pattern.

We needed to share stateful logic in a better way. React is designed to render components, and it doesn't know anything about routing, fetching data, or the architecture of our project.
There wasn't a particular way to reuse stateful component logic and this made the code harder to follow.
So, React Hooks came to the rescue.

![superman.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1608748703615/kLr-bhXay.gif)


Hooks are just functions that are exported from the official React page. They allow us to manipulate components in a different manner.

There are some **rules** about how to use hooks. The following rules are:

1. Only call hooks at the top level of the component.
2. Don't call hooks inside loops, conditionals, or nested functions.
3. Only call hooks from React functional components.
4. Call them from within React functional components and not just any regular Javascript function.
5. Hooks can call other Hooks.

You may ask, _Should I need to change my class components to hooks?_ Actually NO, we can still use class components as 16.8 is backward compatible.

## Application Tools

- [x] Install [NodeJS](https://nodejs.org/en/) and make sure it is the LTS(long term support) version. LTS version is a less stable version of NodeJS. We will use NPM (node package manager) and we will use it to install **create-react-app**.

![node.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1608748738172/0WAY_iUjI.png)

- [x] Install your preferred code editor or IDE. I will be using Visual Studio Code. You can download it from [this website](https://code.visualstudio.com/). It is free to use.

![vscode.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1608748752789/9kTkDVkim.png)

- [x] **create-react-app** is an npm package that we can bootstrap our React application without any configuration.
     
![cra.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1608748771585/b5_Bcigzs.png)

## How to Install React Hooks?

You need to either upgrade the version of React and React-DOM to `16.8.2` or create a new React project using Create React App.

In this tutorial, we’ll use Create React App to create a new React project.

Open up your terminal and run the following to create the new project:

```bash
# cd into the directory you want to create the project.
cd desktop

# type this command to install create-react-app, you can give any name for the app.
npx create-react-app myApp

# Let's go inside our project folder, type the name of our project, and `cd` into it.
cd myApp

# open the project files with Visual Studio or any code editor
# start the app
npm start
```

Your default browser will open and you’ll see your new React app.

![app.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1608748590177/TJTzJvaJZ.png)

Now we can see our app is up and running. Before starting our app, let's make some cleanup and remove some of the files that we will not use.

Let's remove `App.test.js, index.css, logo.svg, setupTests.js` from the `src` folder. You can copy and paste the basic structure for `App.js` and `index.js` from the code snippets below.


```javascript
// src/App.js

import React from 'react';
import './App.css';

function App() {
  return <div></div>;
}

export default App;
```


```javascript 
// src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(<App />, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
```

Also, we can remove `logo` files from the `public` folder, now my files are looking like this:

![fs.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1608748620160/O6A9iOpjO.png)

Throughout this tutorial, we will create multiple components and you need to import the components to `App.js` to see how it is working. I have used `react-router-dom` to show all the components in one app, but we will not talk about routing in this tutorial. That's why you need to create a folder under `src` directory named `components` and create the components there, then import it to `App.js`. Example:


```javascript
// src/App.js

import React from 'react';
// import the new component here
import StateHook from './components/StateHook';

import './App.css';

function App() {
    return (
      <div>
      {/* render the component  */}
        <StateHook />
    </div>
    );
}

export default App;
```


## Styling the Application

I have used [Semantic UI](https://semantic-ui.com/) and custom CSS for styling. For Semantic UI, I have added a `link` tag inside my `public > index.html` file like this:

```html
<link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css" rel="stylesheet" />
```

`className` attribute values are coming from Semantic UI or CSS. You don't need to focus on those.

For the CSS code, you can copy-paste these inside `App.css` file.

```css
/* src/App.css */

body {
  padding: 10px;
  font-family: sans-serif;
  background-color: #f69e9e;
  line-height: 1.2;
}

.container {
  text-align: center;
  margin-top: 5rem;
  width: 90vw;
  margin: 0 auto;
  max-width: 1170px;
  min-height: 100vh;
}

h1 {
  color: #371e30;
  letter-spacing: 10px;
  text-transform: uppercase;
  margin: 0 0 10px;
}

h2 {
  font-weight: bold;
  font-size: 1em;
  line-height: 1.2em;
  padding: 0;
  color: #222;
  font-size: 30px;
}

a {
  text-decoration: none;
  color: #222;
  font-weight: 600;
}

ul {
  vertical-align: bottom;
  margin: 0 20px;
  padding: 0 0 25px 0;
  text-align: left;
}

p {
  font-weight: bolder;
  font-size: 1em;
  text-align: left;
}

input[type='text'] {
  width: 60%;
  padding: 12px 20px;
  margin: 8px 0;
  display: inline-block;
  border-radius: 4px;
  box-sizing: border-box;
  background: #fff;
}

.btn {
  display: block;
  margin: 0 auto;
  padding: 0.25rem 0.75rem;
  border-color: transparent;
  text-transform: capitalize;
  font-size: 1.4rem;
  margin-top: 2rem;
  cursor: pointer;
  background-color: #ddd;
  color: black;
}

.btn:hover,
a:hover {
  border: 1px solid #df57bc;
  background-color: #df57bc;
  padding: 5px;
  color: #fff;
}


.recipe {
  border-radius: 10px;
  margin: 40px;
  min-width: 40%;
  padding: 40px;
  max-width: 400px;
  background: white;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
}
```


Now, with this, we are ready to go. 🥳

## The `useState` Hook

State helps build highly performant web apps. To keep track of our application logic, we need to use `useState`. We can reflect any UI(user interface) changes via changes in state.

`useState` function lets us use state in a functional component.

In order to use `useState` in our component, we have to import `useState` first. `useState` is a named export; so, we will export it with curly braces.

`import React, { useState } from 'react';`

Let's make an example of how to use `useState`.

```javascript

// src/components/StateHook.js
import React, {useState} from 'react';

const StateHook = () => {
  
  const [title, setTitle] = useState('hello world');

// update the state with setTitle function
  const handleClick = () => {
    setTitle('React is cool');
  };

  return (
    <div className="container">
      <h2>{title}</h2>
      <button type="button" onClick={handleClick} className="btn">
        Change title
      </button>
    </div>
  );
};

export default StateHook;

```

![state.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1608749078479/sfTI4Xo-X.gif)

`useState` returns an array of two items:

- the first element is the _current value of the state_.
- the second is a _state setter/updater function_, which we use to update our state.

In short, state tracks the value of our state. The setter function updates the state and rerenders JSX elements.

```javascript
// destructuring an array
// initial state is 'hello world'
const [title, setTitle] = useState('hello world');
```

Developers generally prefer array destructuring with `useState` hook or we need to write more verbose code like this:

```javascript
const items = useState('hello world');
const title = items[0];
const setTitle = items[1];
```

You may ask, _How React knows when to render?_ React components will only rerender when their props or state have changed. Props are passed into a component and read-only, whereas a state holds information about the component, and can be updated. During the initial render, the returned state is the same as the value passed as the first argument (initialState).

So, here we updated our state with the `setTitle` setter function and passed a different string inside of it. When the button gets clicked, we are updating the state with the `onClick event handler`. The `setTitle` function accepts a new state value and rerenders the component. 

In class components, a state is always an object, with the `useState` hook, the state does not have to be an object. Instead, you can break up state into multiple pieces that you can update independently.

## useState with objects

What I mean by the title is we will create an object inside our `useState` hook, instead of passing a string. The initial value of `useState` can be of any type, like an array, an object, a boolean, a number, a string, etc.


```javascript 

// src/components/StateHookObject.js
import React, {useState} from 'react';

const StateHookObject = () => {
  // pass an object for the initial state
  const [name, setName] = useState({firstName: '', lastName: ''});

  return (
    <form>
        <input
          type="text"
          value={name.firstName}
          // set firstName to whatever is typed inside the input field
          onChange={(e) => setName({firstName: e.target.value})}
        />
        <input
          type="text"
          value={name.lastName}
          // set lastName to whatever is typed inside the input field
          onChange={(e) => setName({lastName: e.target.value})}
        />
        <h2>First name is: {name.firstName}</h2>
        <h2>Last name is: {name.lastName}</h2>
    </form>
  );
};

export default StateHookObject;
```

Now, let’s break down the code above to explain what we’ve added and how it works.

- importing the `useState` hook from React
- creating a new constant that returns `name` and `setName` from `useState`.
- initializing the `useState` hook with an object.
- create a `form` to display our inputs and `h2` tags
- add `value` property and `onChange` event handler to our inputs. `e.target.value` will give us the value inside the input field.

The important part about this component, we need to focus on the `onChange` event handler. `onChange` event fires whenever the user types in something.
Whenever the first input value changes, we update the `firstName` property, and when the second input value changes, we update the `lastName` property.

Okay, everything looks perfect. Now, let's test our code.

![demo3.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1608749129218/dZO5keccx.gif)

We have a problem with updating our states; so, as you can see, we can update both input fields; but when we switch between them we cannot keep track of our old state.

Let's add this one line of code to see what is happening.

```javascript 
// src/components/StateHookObject.js

// ...
  <h2>Last name is: {name.lastName}</h2>

// add this line to your code
  <h2>{JSON.stringify(name)}</h2>
  </form>
```

![demo4.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1608749163893/NmpUehJgM.gif)

When we type for the first name input, the last name input is disappearing. **Because state doesn't automatically merge and update the state.** `useState` does not "merge" its arguments with the old state. They just set the state. Every time, with every rerender we don't mutate our state, we get a completely new state, we can change our state with the setter function.

In class components `setState` will merge the state; `useState` hook will not merge the state. To handle this, we will use the `spread operator` to merge. With this, the setter object will copy everything inside the `name` object, and overwrite the `firstName` or `lastName` fields with a different value.

Let's see this in our code:

```javascript 
// src/components/StateHookObject.js

// ...
return (
  <form>
      <input
        type="text"
        value={name.firstName}
        // add the spread operator
        onChange={(e) => setName({...name, firstName: e.target.value})}
      />
      <input
        type="text"
        value={name.lastName}
        // add the spread operator
        onChange={(e) => setName({...name, lastName: e.target.value})}
      />
      <h2>First name is: {name.firstName}</h2>
      <h2>Last name is: {name.lastName}</h2>
      <h2>{JSON.stringify(name)}</h2>
  </form>
);
```

![demo5.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1608749195816/cqMgKwuzk.gif)

- We `shouldn't mutate the state` in our components.
- We need to pass the previous state by the state setter(with the spread operator).

## useState with arrays

![todo.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1608749199856/mY64kl0Un.png)

Now, we will make another component that we will use an array for the initial state. Let's see what will happen.

```javascript 
// src/components/StateHookArray.js

import React, { useState } from 'react';

const StateHookArray = () => {
    const [ items, setItems ] = useState([
      { id: 1, listItem: 'go on a holiday' },
      { id: 2, listItem: 'go hiking' },
      { id: 3, listItem: 'learn React Hooks' }
    ]);

    // remove items
    const removeItem = (id) => {
      setItems(items.filter((item) => item.id !== id));
    };

    const addItem = () => {
      setItems([
        // don't mutate the array, use spread operator to get the previous state
        ...items,
        // add new item
        {
          id: 4,
          listItem: 'meet deadlines'
        }
      ]);
    };

    return (
      <div className="ui container">
        <div className="ui grid">
          {items.map((item) => {
            const { id, listItem } = item;
            return (
              <div key={id} className="row">
                <h2 className="five wide column">{listItem}</h2>
                {/* when it is clicked, remove the individual item */}
                <button className="three wide column btn" onClick={() => removeItem(id)}>
                  remove
                </button>
              </div>
            );
          })}
        </div>
        {/* when it is clicked, empty the whole array */}
        <button className="btn" onClick={() => setItems([])}>
          Delete all
        </button>
        {/* when it is clicked, add one new item to the list */}
        <button className="btn" onClick={() => addItem()}>
          Add Item
        </button>
      </div>
    );
  };

export default StateHookArray;
```

Let’s break down the code above to explain what we’ve added and how it works.

- importing the `useState` hook from React
- creating a new constant that returns `items` and `setItems` from `useState`.
- initializing the `useState` hook with an array of objects.
- returning some JSX elements to display our array items and Semantic UI to add a grid system
- mapping over the array to get each array item 
- adding a remove button for every item when it is clicked, we can remove the individual item 
- adding a button with an `onClick` handler that invokes the `setItems` function of `useState` with an empty array. So, we can remove everything from our array.
- adding an add button, when it is clicked on it adds a new item. We merge the old state with the updated state with the help of ES6 spread operator.

![demo2.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1608749322881/0oOj395nf.gif)

And yes, we are done with the `useState` hook. 🥳

Thanks for your time. Like this post? Consider [buying me a coffee](https://www.buymeacoffee.com/hulya) to support me writing more.