When to use React.useCallback Hook
Tags: react, javascript, webdev, hooks
Published: 2022-08-01 07:51:00

When I first read about the `useCallback` hook I thought I had a great weapon with me to optimise my React app's performance and started using it on every damn function without understanding the limitations or may be I should call it the right concept behind it.

Before diving deep into this topic, let us first understand on a high level what exactly is the `useCallback` hook.

So, basically `useCallback` hook takes a function and a dependency array. It returns the memoized function. A new memoized value of this function is created whenever the value or references of the elements in the dependency array change.

### What if you do not wrap a function using `useCallback`?

When you don't wrap a function with `useCallback`, whenever the component is re-rendered a new instance of the function is created(The function is given a new memory location).

Also, make a note of the below snippet.

```javascript
function add() {
  return (a, b) => a + b;
}
const add1 = add();
const add2 = add();

add1(1, 2); // 3
add2(1, 2); // 3

add1 === add2; // false
```

In the above snippet you can see that though add1 and add2 are created from the same function declaration and give the same output they are not the same because the references of these two functions are different. 

### When to use `useCallback`?

Let us consider an example.

```javascript
function Child({ handler }) {

  return (
    <div onClick={handler}>
        Click Me
    </div>
  );
}

export default React.memo(Child)
```

Below is the Parent component

```javascript
export default function ParentComponent() {
  const [state, setState] = useState(false);
  const [dep] = useState(false);

  const handler = useCallback(
    () => {
      console.log("You clicked handler")
    },
    [dep]
  );
  const statehanddler = () => {
    setState(!state);
  };
  return (
    <>
      <button onClick={statehanddler}>State Change</button>
      <Child handler={handler} />
    </>
  );
```

In the above example we have wrapped the Child component with `React.memo` which means it will re-render the child component only if the props to it change.

`handler` is passed as a prop to the Child component. 

**Let us assume we did not use `useCallback` in the above example.**

In this case whenever we click the State Change button the value of `state` is changed and the parent component is re-rendered. Since, at every re-render there will be a new instance of every function created we would have a new instance of the handler function.

Now, what would happen to the child component? Will it re-render?

In the `add` example I have shown you how does function equality works. By referring to it we can say that the child component will re-render because the `handler` prop now has a new reference. This means that even when we wrap the component with `React.memo` we are a re-rendering the child component.

**Assuming we are using `useCallback`**

`useCallback` hook here will memoize the function passed to it as an argument and it will only create a new instance of the memoized function if the value or reference to an element in the dependency array changes. 

So, clicking on the State Change button will change the value of the state variable `state` but the value inside the dependency array(`dep`) remains same. Hence, there is no new instance of handler created and the child component will not re-render.

### When not to use `useCallback`?

`useCallback` has its own downsides. There are times when using `useCallback` makes no sense.

Let us take an example

```javascript
export default function Parent() {
    
  const clickHandler = useCallback(() => {
      console.log('Click event')
  }, [])

  return <Child onClick={clickHandler} />
}

const Child = ({ clickHandler }) => {
  return <button onClick={clickHandler}>Child Component</button>
}
```

In the above example using `useCallback` makes no sense since we are creating `clickHandler` function on every re-render. Also, optimization might cost us more here because of the `useCallback` check we have to do on every re-render(Recreation of inline functions is generally cheap).

### Conclusion

`useCallback` memoizes functions instead of values, to prevent recreation upon every render. It helps us avoid unnecessary re-rendering and improves performance.

We also should be careful while using `useCallback` because it can cost us a lot if we do not scan our components well before using it.

I hope this helps. If you have any questions and suggestions reach me out on [Github](https://github.com/rak-shit) and [LinkedIn](https://www.linkedin.com/in/mrakshit/).

Follow me on [Twitter](https://twitter.com/mRakshit_)

Have a nice day :)