# A Look At React Hooks: useCallback

Welcome to [A Look at React Hooks](https://hashnode.com/series/a-look-at-react-hooks-ckicwasfb00a0t0s15sv9bd6q), a beginner-friendly series on React Hooks. In this article, let's look at the `useCallback` Hook.

## What is useCallback?
At a glance, it seems that this Hook is pretty straightforward. It accepts 2 arguments: a callback function and an array of dependencies. It returns a **memoized** callback function when any value in the dependency array has changed.

In code, it looks like (from [React Hooks docs](https://reactjs.org/docs/hooks-reference.html#usecallback)):
```javascript
const memoizedCallback = useCallback(
  () => {doSomething(a, b);}, //callback function
  [a, b], //dependency array
);
```
### Memoization
The word 'memoized' or 'memoization' is an optimization technique to speed up expensive function calls by returning **cached results** instead of re-computing if the inputs of the function are the same.

For this Hook, understanding why we need to memoize a callback function is essential, so we know when to use it. So let illustrate that with a simple example.

## An Example
Take a look at this simple app. It consists of 3 components, `Todo`, `Number` and `Counter`.

![Capture.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1614513786810/LUl4z-V1U.png)

The `Todo` component displays items that were passed from props. The `Number` component displays the current value of `number` while the `Counter` component is responsible for the 2 buttons that can change the value of `number`. These 3 components are wrapped inside `App.js` as shown below.
```
function App() {
  console.log("Render App");
  //init items for Todo
  const [items, setItems] = useState([
    "1. Some todo",
    "2. Some todo",
    "3. Some todo"
  ]);
  //init number for Number and Counter
  const [number, setNumber] = useState(0);
  //add items for Todo
  const add = () => {
    setItems(() => [...items, "New todo"]);
  };
  //handler function for Counter
  const increase = () => {
    setNumber(number + 1);
  };
  //handler function for Counter
  const decrease = () => {
    setNumber(number - 1);
  };
  return (
    <div>
      <Todo items={items} add={add} />
      <Number number={number} />
      <Counter incr={increase} decr={decrease} />
    </div>
  );
}
```
As seen in the code, all the states and functions are within `App.js` while the 3 child components are merely acting as separate containers for this example.

In each component, we have a `console.log` statement to track when they are rendered.

**In todo.js**
```
function Todo(props) {
  console.log("Render Todo");
  return (
    <div>
      <h2>My Todo</h2>
      {props.items.map((item) => {
        return <p>{item}</p>;
      })}
      <button onClick={props.add}>Add Todo</button>
    </div>
  );
}
```
**In number.js**
```
function Number(props) {
  console.log("Render Number");
  return (
    <div>
      <h2>Counter</h2>
      <p>The number is: {props.number}</p>
    </div>
  );
}
```
**In counter.js**
```
function Counter(props) {
  console.log("Render Counter");
  return (
    <div>
      <button onClick={props.incr}>Increase</button>
      <button onClick={props.decr}>Decrease</button>
    </div>
  );
}
```
If we run our app, notice in the clip below that the console logs when a component is re-rendered. If we only click the `Counter` buttons and update the `number` value, the `Todo` component also re-renders along with `Number` and `Counter`. It is unnecessary for `Todo` to re-render if its values stay the same.

![pure.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1615346075136/RFBj5IXIy.gif)

It goes for the same when an item is added to the Todo component and the `items` array gets updated. Both Counter and Number gets unnecessarily re-rendered even though they have nothing to do with `items`.

This can be an issue if a component is very huge and needs to load over a hundred items on its list. If it keeps being re-rendered even when its items do not change, it can cause performance issues in the app. There is no need to re-render the components that unrelated to a particular state update.


### Solution
`React.memo()` is a built-in React feature that renders a memoized component and skip unnecessary re-rendering. So each component will only re-render if it detects a change in their props. 

So, we can wrap the component with `React.memo()` in its export line:
```
export default React.memo(Component);
```
Wrap React.memo around the Todo, Number and Counter components. At this point, you might think: Great! That should be all. But let's see the app in action:

![onlymemo.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1615346560483/pyZLlk1QS.gif)

Uh-oh! Why is it still rendering unnecessary components? When the 'Add Todo' button is clicked, we expect only `App` and `Todo` to re-render. Instead, we get `App`, `Todo` and `Counter`, but `Number` is behaving correctly.

#### Why is this so?
Let's go back and see how `App` returns the 3 components.
```
  return (
    <div>
      <Todo items={items} add={add} />
      <Number number={number} />
      <Counter incr={increase} decr={decrease} />
    </div>
  );
```
As you can see, the 3 functions written in `App`: `add`, `increase` and `decrease` are passed as props in `Todo` and `Counter`. Notice that only the value `number` is passed into `Number` as props.

In React, whenever a component re-renders, a new instance of the function in it gets generated. Therefore, every time `App` renders, `add`, `increase` and `decrease` are re-created. So their references now points to different functions in memory. Hence, in terms of **referential equality**, the functions before re-render are not the same as the functions after the re-render. See diagram below to visualize.

![re.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1615352906634/2YrauRcfK.png)

As a result, when 'Add Todo' button is clicked:
1. `App` gets re-rendered. 
2. The `items` array and the references for `add`, `increase` and `decrease` gets updated.
3. React.memo accounts for these changes and re-renders the components with `items`, `add`, `increase` and `decrease` as their props.

On the other hand, `Number` does not get re-rendered when 'Add Todo' button is clicked because there is no change to the `number` prop.

So how do we prevent the reference of the functions the same?

### useCallback to the rescue

As previously mentioned, the Hook takes a callback function as its argument and a dependency array as its second. To solve the issue in our example, we simply need to wrap our handler functions in `App.js`: `add`, `increase` and `decrease` inside the Hook. This prevents the unnecessary re-rendering behaviour because it ensures the **same callback function reference** is returned when there is no change in their dependency. 

For example, let's edit the `add` function first.
```javascript
 //add items for Todo - before
 const add = () => {
    setItems(() => [...items, "New todo"]);
 };
 //add items for Todo - after
 const add = useCallback(() => {
    setItems(() => [...items, "New todo"]);
 }, [items])
```
Now, the function `add` will only be updated if `items` change. Do the same for `increase` and `decrease` functions. These functions should only be updated when `number` changes. They should look like:

```javascript
const increase = useCallback(() => {
    setNumber(number + 1);
}, [number]);

const decrease = useCallback(() => {
    setNumber(number - 1);
}, [number]);
```

### Result 
![solved.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1615349892714/7xoDTDOAX.gif)

Yay! Now only the relevant components will re-render. `add` only result in `Todo` updating and re-rendering. And `increase` or `decrease` will re-render `Number` and `Counter` components.

![3.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1615352954955/iQEzyNK8n.png)

## Conclusion
And that's the gist of this Hook! Thanks for reading this article. I hope it was helpful for React beginners. Please feel free to ask questions in the comments below. Ultimately, practising and building projects with this Hook will help anyone to pick it up faster.

The next Hook in this series will be: `useMemo`. It will be the last basic Hook in this series. After that, this series will continue for advanced/custom Hooks. Stay tuned and cheers!

-------------

### Resources
- https://reactjs.org/docs/hooks-reference.html#usecallback
- https://reactjs.org/docs/hooks-faq.html#are-hooks-slow-because-of-creating-functions-in-render
