React Hooks
Tags: react, reactnative, programming
Published: 2022-09-14 16:47:58

**Hooks** were introduced to React 16.8. Hooks allow you to use things like state without writing a class-based component. In essence, Hooks are JavaScript functions that allow you to "hook into" React state and lifecycle features from function components. There are a number of built-in Hooks as well as the ability to write your own custom Hooks. 

> Note: It's important to remember that Hooks are backwards compatible, so you can use them with class components without a problem. 

All React Hook names are prefixed with the word "use," like `useState` or `useEffect`. To use Hooks, you must import them first. You can enter any number of Hooks at the top of the file like so:

```jsx
import React, { useState, useEffect } from "react";
```

### Why use hooks?

When compared to class components, hooks reduces the amount of code we need to write (and read). Take a look at this example: 

{% embed https://twitter.com/threepointone/status/1056594421079261185?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1056594421079261185%7Ctwgr%5E6e5eeacf097ded5033dac8c25b94088d9ec16f1c%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fcdn.embedly.com%2Fwidgets%2Fmedia.html%3Ftype%3Dtext2Fhtmlkey%3Da19fcc184b9711e1b4764040d3dc5c07schema%3Dtwitterurl%3Dhttps3A%2F%2Ftwitter.com%2Fthreepointone%2Fstatus%2F1056594421079261185image%3Dhttps3A%2F%2Fi.embed.ly%2F1%2Fimage3Furl3Dhttps253A252F252Fpbs.twimg.com252Fmedia252FDqnGs6yWwAAYPXp.jpg253Alarge26key3Da19fcc184b9711e1b4764040d3dc5c07 %} 

With Hooks we can organize logic inside of a component. These units can be reusable, helping us avoid duplicated logic. [Dan Abramov](https://overreacted.io/) writes that "Hooks apply the React philosophy (explicit data flow and composition) _inside_ a component, rather than just _between_ the components." Hooks are fully **encapsulated**, and are a way to share stateful logic. 

{% embed https://twitter.com/seldo/status/1057030555202535424?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1057030727512911874%7Ctwgr%5E2425f88d68d273d2e92277a54237a3cd8dc6c186%7Ctwcon%5Es2_&ref_url=https%3A%2F%2Fcdn.embedly.com%2Fwidgets%2Fmedia.html%3Ftype%3Dtext2Fhtmlkey%3Da19fcc184b9711e1b4764040d3dc5c07schema%3Dtwitterurl%3Dhttps3A%2F%2Ftwitter.com%2Fseldo%2Fstatus%2F1057030727512911874image%3Dhttps3A%2F%2Fi.embed.ly%2F1%2Fimage3Furl3Dhttps253A252F252Fpbs.twimg.com252Fprofile_images252F1023674214304309249252FzzjjK5xh_400x400.jpg26key3Da19fcc184b9711e1b4764040d3dc5c07 %}

Here are some reasons to use Hooks from [Shedrack Akintayo](https://www.smashingmagazine.com/author/shedrack-akintayo/)

- Improved code reuse
- Better code composition
- Better defaults
- Sharing non-visual logic with the use of custom Hooks
- Flexibility in moving up and down the components tree

---

### Rules

There are **two important rules** for using Hooks: 

- **Only call Hooks at the top level**. Don't call Hooks inside of loops, conditions, or nested functions. 

- **Only call Hooks from React functions**. Do not call Hooks from regular JavaScript functions. You can and should call Hooks from React function components. You may also call Hooks from other custom Hooks. 


> There is a plug-in called esLint which will enforce the rules of Hooks. Find and install it [here](https://www.npmjs.com/package/eslint-plugin-react-hooks)!

You **can** use multiple Hooks in a single component, and React will rely on the order in which Hooks are called. Dan Abramov also states: 

> The ability to pass data between Hooks make them a great fit for expressing animations, data subscriptions, form management, and other stateful abstractions. **Unlike render props or higher-order components, Hooks don’t create a “false hierarchy” in your render tree.** They’re more like a flat list of “memory cells” attached to a component. No extra layers.

---

### Built-in Hooks

React has 10 built-in Hooks, here are some of the more commonly used ones: 

--- 

#### useState

The `useState` Hook is called inside of a function component to add local state to it. It allows you to create, update, and manipulate state inside the functional component it is used in. `useState` returns a destructured array containing two values: the first is the current state; the second is a setter function used to update the state. `useState` takes a single argument, which is it's initial state.

```jsx
const [state, setState] = useState(initialState);
```

Here is an example of a simple counter: 

```jsx
import React, { useState } from "react";

function Counter(){
    // The new state variable is called "count" here, and the initial value will be 0 since the counter will begin at 0.
    const [count, setCount] = useState(0);

    return (
       <div>
          <p>The button was clicked {count} times!</p>
          <button onClick={() => setCount(count + 1)}>
               Click to Count
          </button>
       </div>
    );
}
```

The new state variable is called `count`, and the setter function is called `setCount`. You can call these two variables anything you'd like, but this is the typical naming convention: use "set" concatenated with the variable name. The initial state is set to 0 since we want the counter to begin at 0. The `setCount` function will be called each time the button is clicked, and update the count variable by 1. React will remember the current value of `count` between re-renders, and provide the most recent one to the function component. If we want to update it, we just call `setCount` again. 

As you can see, `setCount` was called inside of the function's return, namely in the JSX code of the button's `onClick`. This is perfectly fine!  

You can use the state 
Hook multiple times in a single function component: 

```jsx
function ManyStatesExample() {
    const [name, setName] = useState("Jimmy");
    const [age, setAge] = useState(35);
    const [favoriteColors, setFavoriteColors] = useState(["red", "blue"]);
```

> Note: Updating a state variable replaces it's contents. 
 
---

#### useEffect

The `useEffect` Hook replicates React's lifecycle methods, but inside of a functional component. The official React documentation states: "If you’re familiar with React class lifecycle methods, you can think of `useEffect` Hook as `componentDidMount`, `componentDidUpdate`, and `componentWillUnmount` combined." The `useEffect` Hook lets you perform **side effects** (such as external API interactions and data fetching). `useEffect` accepts two arguments: 
- A function with the code to run
- A **dependency array**, which tells the Hook how many times to run. If this is left out, the Hook will run after every render. Be careful, leaving out the dependency array can cause infinite loops! 

If you only want to run the `useEffect` Hook when certain values in your function have changed, you must pass the variables as dependencies into the array. If you supply an empty array, the Hook will only run once. This can be very useful for things such as fetch requests:

```jsx
useEffect(() => {
    fetch("http://somelink.com");
}, []);
```

The dependency array is empty because we only need to GET our data once. 

Sometimes the `useEffect` Hook can require **cleanup**, which is written about in some detail in the [React docs](https://reactjs.org/docs/hooks-effect.html). 

---

#### useContext 

The `useContext` Hook allows you to make particular data accessible to all components throughout the whole of the application (consider it "global" in scope for a tree of React components). It works with the [React Context API](https://reactjs.org/docs/context.html). This Hook is powerful because data can be passed across all components in an app, rather than having to manually pass a prop down through various levels to get data to a child. 

For example, let's say you have an array of objects, and would like to pass that information down to a child function. 

```jsx
const menuItems = [
{ 
   dish: "spaghetti and meatballs",
   price: "$12.99",
},
{  
   dish: "steak and potatoes",
   price: "$29.99",
},
];

export const MenuContext = React.createContext(menuItems);

```
We are creating a context object using `React.createContext` and now can pass `menuItems` to any components in the app. Each context needs to be enclosed in a Provider wrapper, like so:

```jsx
function Menu() {
    return (
    <MenuContext.Provider value={menuItems}> 
        <DinnerMenu />
    </MenuContext.Provider>
);
}
```

Now `DinnerMenu` becomes the consuming component of the context, and can use the objects stored in the MenuItems array. When the Provider updates, the Hook will trigger a rerender with the latest context value. See React's [advanced Context guide here](https://reactjs.org/docs/context.html).

---

#### useReducer

`useReducer` can be thought of as an alternative to the `useState` Hook. The `useReducer` Hook can work with more complex logic, and lets you rerender the UI whenever values change within the Hook. It accepts two arguments: a reducer function and an initial state. 

`useReducer(reducerFunction, initialState);`

Much like `useState`, `useReducer` returns an array of two values, which can be destructured to: the current value of the state; and a dispatch function. 

```jsx
const [state, dispatchFunction] = useReducer(reducerFunction, initialState);
```

`state` is the current value of the initialState passed to the Hook. The `reducerFunction` accepts the state and an action. These two arguments will determine how the value of the state will change. The `dispatchFunction` is how an action is passed to the `reducerFunction`. There is usually a switch statement with a number of cases to determine how the value of state will change. Here is an example of a simple counter from the [official documentation](https://reactjs.org/docs/hooks-reference.html#usecontext): 

```jsx
const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}
``` 

> Note: React guarantees that **dispatch** function identity is stable and won’t change on re-renders. This is why it’s safe to omit from the `useEffect` or `useCallback` dependency list.

#### useRef

The `useRef` Hook allows you to persist values between renders. You can store a mutable value that does **not** cause a re-render when updated. `useRef` returns an Object called `current`. Consider `useRef` like a "box" that can hole a mutable value in this `current` property. 

You can use this Hook to keep track of previous state values, because `useRef` persists it's values between renders. Consider the following example from [W3Schools](https://www.w3schools.com/react/react_useref.asp): 

```jsx
import { useState, useEffect, useRef } from "react";
import ReactDOM from "react-dom/client";

function App() {
  const [inputValue, setInputValue] = useState("");
  const previousInputValue = useRef("");

  useEffect(() => {
    previousInputValue.current = inputValue;
  }, [inputValue]);

  return (
    <>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
      <h2>Current Value: {inputValue}</h2>
      <h2>Previous Value: {previousInputValue.current}</h2>
    </>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
```

See [this blog post](https://dmitripavlutin.com/react-useref-guide/) by Dmitri Pavlutin for more information and use cases of `useRef`.
 
---

### Other Built-in Hooks

- useCallback
- useMemo
- useImperativeHandle
- useLayoutEffect
- useDebugValue

--- 

### Build Your Own Hooks

Along with these Hooks you can write your own custom Hooks that let you extract component logic into reusable, sharable functions. Because both components and Hooks are functions, you can extract the logic to a third, shared function (a new Hook!). A **custom Hook** is a JavaScript function whose name starts with "use" and that may call other Hooks. It still follows the rules of built-in Hooks, but you get to decide which arguments it will take and what it should return. 

For more information on building custom Hooks, see: [Building Your Own Hooks](https://reactjs.org/docs/hooks-custom.html). 

---

#### Further Reading:

- [Hooks at a Glance](https://reactjs.org/docs/hooks-overview.html)
- [The Guide to Learning React Hooks](https://www.telerik.com/kendo-react-ui/react-hooks-guide/)
- [Getting Started With the React Hooks API](https://www.smashingmagazine.com/2020/04/react-hooks-api-guide/)
- [Writing Your Own Custom React Hooks](https://blog.bitsrc.io/writing-your-own-custom-hooks-4fbcf77e112e)