useCallback: Guide, use-cases, examples
Tags: react, webdev, javascript, tutorial
Published: 2023-08-16 23:57:38

This is an easy to read guide, where we will cover

* What is React `useCallback`?
    
* When to use React `useCallback`? (use-cases)
    
* Real world examples of `useCallback`
    
* TroubleShooting Tips
    

## What is React useCallback

useCallback is a React Hook. (Hooks are JS functions that let's you add additional pre-built functionality to your component)

`useCallback` is a hook that lets you cache a function definition between renders.

`useCallback` does not call the function and cache the return value. It caches the function definition itself.

## useCallBack Reference

`useCallback(function, [dependencies]);`

As `useCallback` is a react Hook you need to call it at the top level of your component

```javascript
import { useCallback } from 'react';

export default function ReactCommentsSection({ postId, username }) {
  const handleCommentSubmission = useCallback((Text) => {
    post('/post/' + postId + '/comment', {
      username,
      comment: commentText,
    });
  }, [postId, username]);
}
```

Parameters

#### fn : (function to memorize)

This is the function that you want to cache.

This function can take any arguments and can return any data

The React will return this function definition (but not call it) during the first render.

On the next renders:

* If the `dependencies` are not changed then the react will give you the same cached function
    
* Else if, dependencies have changed the react will give you the current function that you have passed it. That is if the dependencies have changed.
    

#### Dependencies

An array of reactive values that the function depends on or are referenced by the  `fn`

Reactive values are props, state and all the variables/ functions that are inside your component

The react will do a shallow check to with the [`Object.is`](http://Object.is) method to check if the dependencies have changed

You can use code linter to verify if all the dependencies are listed in the dependencies array

The list of dependencies should remain constant and will be written in line in an array like `[dep1, dep2, dep3]`

#### What does use callback Return

* **initial Render**: On initial render the `useCallback` hook returns the function that you have passed it
    
* **Subsequent Renders** :
    
* If the dependencies have not changed, it will return the cached function
    
* If the dependencies have changed, it will return the new function, that is the function you have passed during this render
    

#### Caveat

Always declare `useCallback` at the top of your component because it is a hook

`useCallback` should never be used inside loops or conditionals. If you need to use it inside loops or conditions, extract the code into a new component

#### Cache Management

* React will not throw away a cached function unless there is a very good reason to do that
    
* like: during development react will through a cached function, if you edit the component
    
* If a component suspends the during initial mounting phase then the react will discard the cached
    

## Examples and Use-cases

### Use-Case : Skipping Re- rendering of components for performance optimization

### 1\.  un-possessory re-renders

When developing large-scale applications or applications with complex logic, it becomes necessary to optimize performance.

Because of resource limitations, the logic or the scale of component and prop drilling can cause the UI to not perform optimally

## Caching the Values or Function

One of the methods of optimizing performance is caching the values that require a lot of computation and that don't change much from one re-render to another

you can use the `useMemo` for caching the values, but what about functions?

As `{}` notation creates a new Object, the function notation like `function () {}` or `() => {}` creates a new function

Normally this isn't an issue but creating new function on every re render defeats the purpose of caching

So, we need to cache the functions that we are passing down as props here `useCallback` comes in handy

### Example 1 : The Comment section

Consider a comment section on a website. Here we have `CommentSection` Component

```javascript
import { useCallback } from 'react';

export default function CommentSection({ userName, userToken, postId, }) {
  const handleCommentSubmission = useCallback((textOfTheComment) => {
    post('/post/' + postId + '/comment', {
      username,
      comment: textOfTheComment,
      token: userToken,
    });
  }, [postId, userName, userToken]);
}
```

Here we have a `CommentSection` Component. Our component takes three props : 1. `userName`, `userToken`, and `postId`

Then we have the `handleCommentSection` function that has the `useCallback` hook to which checks if any of the dependencies in the dependencies array has changed

the dependencies are : `[postId, userName, userToken]`

If the dependencies have not changed then the `useCallback` returns the cached function otherwise the `useCallback` returns the new function

## When to use useCallback vs useMemo?

Both useCallback and useMemo are used to cache something to optimize performance

useMemo is used to cache values and useCallback is used to cache function definitions

So, as to prevent unnecessary re-renders

## Difference of useMemo with useCallback

The `useMemo` hook takes a function and a dependency array as arguments

The `useMemo` calls the function and caches its returned **value**, the function is then only called when any of the dependencies change

```javascript
const ComponentCompute = useMemo(() => {
  return calculateReq(product);
}, [product]);
```

here the returned value of `calculateReq` will be cached and this will only be re-calculated when the `product` changes

`useCallback` also takes a function and a dependency array, but instead of caching the return value of the function it caches the **function declaration** itself

**useMemo**

```bash
  const requirements = useMemo(() => { // Calls your function and caches its result   
 return computeRequirements(product);  }, [product]);
```

**useCallback**

```javascript
import { useCallback } from 'react';

export default function CommentSection({ userName, userToken, postId, }) {
  const handleCommentSubmission = useCallback((textOfTheComment) => {
    post('/post/' + postId + '/comment', {
      username,
      comment: textOfTheComment,
      token: userToken,
    });
  }, [postId, userName, userToken]);
}
```

When the `handleCommentSubmission` function gets called, useMemo calls the cached version and that remains the same across renders except when one of the dependencies change

If you are familiar with useMemo then you can think of useCallback as a wrapper around useMemo with built in functionality

you can use useMemo instead of useCallback by adding a callback function like so

```javascript
function useCallback(fn, dependencies) {
  return useMemo(() => fn, dependencies);
}
```

## When to use useCallback

It depends on what type of app or website you have. If you have an app that is more like a website, that is you are changing Big parts or your UI at once then memorization of caching is not that useful

And if you only need to change small parts of your overall UI like in a drawing application or some other app

Where you load a whole lot of UI at once and then need to make small changes to the UI then caching would be a good strategy

### Here are a few cases where useCallback is a good idea'

1. If you are using `useMemo` in a component and you want to pass a function to that component as prop.
    
2. If you are using the function inside other React Hooks. For `example` another function wrapped in `useCallback` depends on it you depend on this function from `useEffect`
    

**Note:** The `useCallback` does not prevent from creation a function. the function is always created and that is all good, React just ignores the created function and provides you with the cached version instead

### Making Memorization and caching unnecessary by following a few principles:

1. **Wrap a component visually**
    

When a component is visually wrapping other components like a big web page component containing smaller UI components like buttons etc

Let it accept JSX as its children. like so,

```javascript
<div>
  <img />
    <button />
</div>
```

Then if the wrapper component updates react know not to update the child components.

2\. **Local State**

Always prefer local state and do not lift the state. Only lift the state when necessarily required.

So this importantly with short lived data like when a user is hovering over a  button or there is a small form

3\. **Keeping the rendering logic pure**

The component should always be pure. Meaning for a given input props the output should always remain the same

or re-rendering the component should never give different outputs

Fix the bug instead of caching the component

4\. **Avoid unnecessary effects that update state**

Effects are updates that the application asks react to perform after the UI update is over. However if there are lots of updates then it makes the app run in circles and causes performance issues

hence, only use updates when necessary

5\. **Removing unnecessary dependencies from your effects**

instead of caching the values and the function declaration, you can try to reduce the dependencies like move out some objects or function

IF the interaction is still laggy use the React dev tools profiler to find out which components can benefit from memorization

## The difference between useCallback and declaring a function directly

1. Declaring a function directly
    

Directly declaring a function inside a component, creates a new instance of the function every time the component re renders. This is because as `{}` creates a new Object a new functional declaration like `function (){}` or `()=>{}` creates a new function

```javascript
function SomeComponent(props) {
  function handleClick() {
    console.log('Somebody clicked the button');
  }

  return <button onClick={handleClick}>Click the button		</button>;
}
```

Here everytime the SomeComponent is rendered on screeen a new `handleClick` button is created.

2\. **useCallback**

the `useCallback` hook memorizes the function defination itself. Now, when the `SomeComponent` is rendered on the screen the useCallback gives you the cached version of the `handleClick` method

```javascript
import { useCallback } from 'react';

function SomeComponent(props) {
  const handleClick = useCallback(() => {
    console.log('user clicked button');
  }, []);  // function get recreated when dependencies change, here the array is empty meaning the function will never be recreated

  return <button onClick={handleClick}>Click the Button!</button>;
}
```

Using the useCallback the handleClick method is only created once and cached by the react and the cached copy will always be used thus improving performance

This article is brought to you by DeadSimpleChat, [Chat API](https://deadsimplechat.com) and SDK for your website and apps.

#### Main Difference

* Directly creating a function will create a new instance of the function every time the component re-renders
    
* `useCallback` will cache the function and reuse the function definition thus giving the cached copy every time
    

## Updating state from a memoized callback

In React you can update the state of a component using the setState function.

There are two options when you need to update the state based on the previous state

1. Reading the current state from inside the callback
    
2. using an updater function
    

#### Reading the current state from inside the callback

```javascript
const handleTodo = useCallback((todoText) => {
  const newTodo = { id: nextId++, todoText };
  setTodos([...todos, newTodo]);
}, [todos]);
```

Here

* We are memorizing or caching the handleTodo function with `useCallback`
    
* the `todos` state variable is specified as a dependency because we are reading the state directly
    
* Here every time the todos change a new version of handleTodo will be created
    

#### using an updater function without direct dependency on state

```javascript
const handleAddTodo = useCallback((text) => {
  const newTodo = { id: nextId++, text };
  setTodos(todos => [...todos, newTodo]);
}, []);
```

* Here instead of reading the `todos` inside of reading the todos directly and hence creating the nessissity of adding it as a dependency in the the dependencies array of useCallback
    
* we are providing an updater function.  This updater `func` takes the previous todos as an argument and calculates the new todos state
    
* Thus the benefit here is that the handleTodo now no longer needs to update whenever todos changes thus using the cached version more and improving the performance
    

## Preventing an Effect from firing too often

Many times you have use the `useEffect` hook and you need to call a function inside the hook

This creates a problem, every value must be declared in the dependency array.

To optimize the `useEffect` and component rendering for performance purposes you can wrap the function that you are calling from `useEffect` into `useCallback`.

## Optimizing a Custom Hook

Hooks are functions designed to encapsulate reusable functionality. This is why you can also create custom hooks of your own, this promotes code reusability and maintainability

1. **Need for optimization in custom Hooks**
    

There is a need for optimization in custom hooks that return functions.

This is because these hooks can become problematic for components that have the returned function as a dependency.

The re creation of these functions at every render of the component could cause performance issues

2\. `useCallback` for stable functions

 You can use the `useCallback` hook to cache these functions thus optimizing performance.

## Conclusion

In this article, we learned about the `useCallback` react hook with use-cases and examples

I hope you liked the article. Thank you for reading.