Boosting React Performance: useCallback vs. useMemo Hooks
Tags: wedev, react, productivity, tips
Published: 2023-09-11 06:30:24

---
title: Boosting React Performance: useCallback vs. useMemo Hooks
published: true
date: 2023-08-30 11:03:26 UTC
tags: wedev, react, productivity, tips
canonical_url: https://www.syncfusion.com/blogs/post/react-usecallback-vs-usememo-hooks.aspx
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e0wkmp7rux96lzgwom93.png
---
[React](https://en.wikipedia.org/wiki/React_(software) "Wikipedia Link: React (software)") is a popular JavaScript framework for front-end development that has made developers’ lives easier by introducing component-driven development.

Before React 16, components were usually defined with **Class** and had different lifecycle methods. React 16 promoted the creation of functional components and introduced the following [hooks](https://en.wikipedia.org/wiki/React_(software)#React_Hooks "Wikipedia Link: React Hooks"):

- **useEffect** for handling the component’s lifecycle.
- **useState** for state management.

These hooks are necessary because re-renders and re-computations are costly operations, so minimizing them improves the application’s performance.

React has recently introduced two hooks, **useCallback** and  **useMemo**. Like the useEffect and useState hooks, these are potent tools that can help developers optimize the performance of their applications by reducing unnecessary re-renders and re-computations.

In this blog, we will delve into these hooks, exploring their functionality and examining how they work. We will also discuss the appropriate use cases for these hooks, providing practical examples to help you understand when and where to use them in your projects. Let’s get started!

## useCallback hook

Syntax

```js
const computedFn = useCallback(()=>{
  doSomething(dependencies);
}, [dependencies]);
```

In the previous code example, **doSomething(dependencies);** will be returned and stored in the **computedFn** variable. This only occurs only when the dependencies change, and **useCallback** will then provide the new **doSomething(dependencies);** value.

This is useful when you want a function to avoid re-rendering whenever the component changes.   
  
For example, we will use the **debounce** function on the input field to get the data only when the user stops writing for a specific amount of time.

```js
import React, { useState } from "https://esm.sh/react@18.2.0";
import ReactDOM from "https://esm.sh/react-dom@18.2.0";

const App = () => {
  const [text, setText] = useState("");

  const debounce = (func, delay) => {
	let inDebounce;
	return function () {
  	const context = this;
  	const args = arguments;
  	clearTimeout(inDebounce);
  	inDebounce = setTimeout(() => func.apply(context, args), delay);
	};
  };

  const makeApiCall = () => {
	console.log(text, " Making an API call");
  };

  const debouncedApiCall = debounce(makeApiCall, 500);

  const onChangeHandler = (e) => {
	setText(e.target.value);
	debouncedApiCall();
  };

  return (
	<div>
  	<input type="text" onChange={onChangeHandler} value={text} />
	</div>
  );
};

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

Every time the state is updated, the component re-renders, and the debounce function is reattached to the **debouncedApiCall** variable. As a result, the logs are printed every time the state changes, and the **debounce** needs to be fixed.

To avoid this, we can wrap the **debounce** function inside **useCallback** , and the program will write the memoized debounce function that will change only if dependencies change.

```js
import React, { useState, useCallback } from "https://esm.sh/react@18.2.0";
import ReactDOM from "https://esm.sh/react-dom@18.2.0";

const App = () => {
  const [text, setText] = useState("");

  const _debounce = (func, delay) => {
	let inDebounce;
	return function () {
  	 const context = this;
  	 const args = arguments;
  	 clearTimeout(inDebounce);
  	 inDebounce = setTimeout(() => func.apply(context, args), delay);
	};
  };

  const makeApiCall = (e) => {
	console.log(e, "Making an API call");
  };

  const debounce = useCallback(_debounce(makeApiCall, 2000), []);
 
  const onChangeHandler = (e) => {
	setText(e.target.value);
	debounce(e.target.value);
  };

  return (
	<div>
  	<input type="text" onChange={onChangeHandler} value={text} />
	</div>
  );
};

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

We don’t want to re-render the **\_debounce** function, so we are not passing any dependencies. This code will print the log only when the user has stopped writing, and 2000 ms have passed. Notice in the code that we are passing the value to **debounce(e.target.value)** because it cannot pull the value of the state.

Even though it seems to be working fine, it is not. If you have **ESLint** enabled, you will notice that we are getting the following linting error for the **useCallback** hook:

**error React Hook useCallback received a function whose dependencies are unknown. Pass an inline function instead  react-hooks/exhaustive-deps**

This is because the dependencies of the function that **useCallback** is taking as input are not known, so **ESLint** wants us to write an inline function.

Also, the **_debounce** function is re-created on every re-render, thus changing its reference and defeating the purpose of caching it.

To fix this, we can create a custom **useDebounce** hook and use it.

```js
import { useState, useCallback, useRef } from "react";
const useDebounce = (func, delay) => {
  const inDebounce = useRef();
  const debounce = useCallback(
	function () {
  	const context = this;
  	const args = arguments;
  	clearTimeout(inDebounce.current);
  	inDebounce.current = setTimeout(() => func.apply(context, args), delay);
	},
	[func, delay]
  );
  return debounce;
};
const App = () => {
  const [text, setText] = useState("");
  const makeApiCall = useCallback((e) => {
	console.log(e, "Making an API call");
  }, []);
  const debounce = useDebounce(makeApiCall, 2000);
  const onChangeHandler = (e) => {
	setText(e.target.value);
	debounce(e.target.value);
  };
  return (
	<div>
  	<input type="text" onChange={onChangeHandler} value={text} />
	</div>
  );
};
```

## useMemo hook

Syntax

```js
const computedValue = useMemo(()=>{
  doSomething();
}, [dependencies]);
```

**useMemo** works similarly to the **useCallback** , but rather than returning the function, it returns the computed value from the function, i.e. the function’s output, and only recomputes the function when the dependencies change to provide the new result.

For example, let’s say we have a child component that should render only when the text has a specific value.

```js
import React, { useState, useCallback } from "https://esm.sh/react@18.2.0";
import ReactDOM from "https://esm.sh/react-dom@18.2.0";

const ChildComponent = ({ text }) => {
  return <p>{text}</p>;
};

const App = () => {
  const [text, setText] = useState("");

  const onChangeHandler = (e) => {
	setText(e.target.value);
  };

  return (
	<div>
  	<input type="text" onChange={onChangeHandler} value={text} />
  	<ChildComponent text={text} />
	</div>
  );
};

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

If the conditional check were placed within the child component, it would trigger a re-render each time the parent’s state updates, regardless of our intention to limit it to certain values.

The **useMemo** hook addresses this. By employing this hook, the child component becomes memoized, ensuring it only re-renders when the conditions specified in its dependencies are satisfied.

In this instance, the child component will exclusively render when the text matches the term “syncfusion.”

```js
import React, { useState, useMemo } from "https://esm.sh/react@18.2.0";
import ReactDOM from "https://esm.sh/react-dom@18.2.0";

const ChildComponent = ({ text }) => {
  return <p>{text}</p>;
};

const App = () => {
  const [text, setText] = useState("");

  const onChangeHandler = (e) => {
	setText(e.target.value);
  };
 
  const memoizedChildComponent = useMemo(() => <ChildComponent text={text} />, [text === 'syncfusion'])

  return (
	<div>
  	<input type="text" onChange={onChangeHandler} value={text} />
  	{memoizedChildComponent}
	</div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));
```
## Conclusion

Thanks for reading. This blog delved into the two most potent React hooks, namely **useCallback** and  **useMemo** , explaining their functions and exploring their optimal application to sidestep redundant computations when React components re-render.

I encourage you to explore these exceptional features and share your experience in the comment section below.

Have you experienced Syncfusion? Feel free to download the product setup [here](https://www.syncfusion.com/account/downloads/studio/ "Essential Studio Licence and Downloads page"). If you’re new to Syncfusion, enjoy a complimentary [30-day trial](https://www.syncfusion.com/downloads/ "Free evaluation of the Essential Studio products").

Should you need assistance, don’t hesitate to reach out via our [support forums](https://www.syncfusion.com/forums "Syncfusion Support Forum"), [support portal](https://support.syncfusion.com/ "Syncfusion Support Portal"), or [feedback portal](https://www.syncfusion.com/feedback/ "Syncfusion Feedback Portal"). We’re dedicated to aiding you at every step!

## Related blogs

- [The Power of React’s Virtual DOM: A Comprehensive Explanation](https://www.syncfusion.com/blogs/post/react-virtual-dom.aspx "Blog: The Power of React’s Virtual DOM: A Comprehensive Explanation")
- [React useState Vs. Context API: When to Use Them](https://www.syncfusion.com/blogs/post/react-usestate-vs-context-api.aspx "Blog: React useState Vs. Context API: When to Use Them")
- [Launch a React App in a Docker Environment](https://www.syncfusion.com/blogs/post/launch-react-app-in-docker.aspx "Blog: Launch a React App in a Docker Environment")
- [Zero-Bundle-Size React Server Components—An Overview](https://www.syncfusion.com/blogs/post/zero-bundle-size-react-server-components.aspx "Blog: Zero-Bundle-Size React Server Components—An Overview")