---
title: Bitovi Academy - Optimization Hooks
description: Learn how to optimize your React apps with `useMemo` and `useCallback`.
---

- ![AI implementation](https://www.bitovi.com/hubfs/AIConsultingIcon.svg)
  
  [AI implementation](https://www.bitovi.com/services/ai-consulting?hsLang=en-us)
- ![Systems engineering](https://www.bitovi.com/hubfs/icon%20-%20backend.svg)
  
  [Systems engineering](https://www.bitovi.com/services/systems-engineering-consulting?hsLang=en-us)
- ![Project management](https://www.bitovi.com/hubfs/icon%20-%20PM.svg)
  
  [Project management](https://www.bitovi.com/services/agile-project-management-consulting?hsLang=en-us)
- ![Product design](https://www.bitovi.com/hubfs/icon%20-%20design.svg)
  
  [Product design](https://www.bitovi.com/services/product-design-consulting?hsLang=en-us)
- ![Frontend development](https://www.bitovi.com/hubfs/icon%20-%20frontend.svg)
  
  [Frontend development](https://www.bitovi.com/services/frontend-development-consulting?hsLang=en-us)
- [View more
  
  →
  
  ](https://www.bitovi.com/digital-consulting-services?hsLang=en-us)

We're Experts in...

- [JavaScript](https://www.bitovi.com/services/frontend/javascript-consulting?hsLang=en-us)
- [AI training](https://www.bitovi.com/ai-training-for-software-engineers?hsLang=en-us)
- [Angular](https://www.bitovi.com/services/frontend/angular-consulting?hsLang=en-us)
- [Design Systems](https://www.bitovi.com/services/axure-figma-migration?hsLang=en-us)
- [React](https://www.bitovi.com/services/frontend/react-consulting?hsLang=en-us)
- [Temporal](https://www.bitovi.com/services/backend/temporal-consulting?hsLang=en-us)
- [React Native](https://www.bitovi.com/services/frontend/react-consulting/react-native?hsLang=en-us)
- [Node.js](https://www.bitovi.com/services/backend/nodejs-consulting-1?hsLang=en-us)

Showcase

![Yum! Brands](https://www.bitovi.com/hubfs/yum-showcase-link-1.png)

[View case study](https://www.bitovi.com/en/bitovi-yum-case-study?hsLang=en-us)

More Projects

- [![Levi's](https://www.bitovi.com/hubfs/levis.svg)](https://www.bitovi.com/web-application-consulting-work/levis-ecommerce-responsive-redesign?hsLang=en-us)
- [![Christie's International Real Estate](https://www.bitovi.com/hubfs/christies.svg)](https://design.bitovi.com/christies)
- [![BAFS](https://www.bitovi.com/hubfs/bafs.svg)](https://www.bitovi.com/ux-design-consulting/ux-case-studies/bafs-ppp?hsLang=en-us)
- [View more
  
  →
  
  ](https://www.bitovi.com/our-software-consulting-work?hsLang=en-us)

Open Source Tools

We build powerful tools and open source them to support the community.

[See what we've built →](https://www.bitovi.com/open-source?hsLang=en-us)

- [![Blog](https://www.bitovi.com/hubfs/icon%20-%20blog.svg)
  
  BlogWe post about perfecting software delivery
  
  ](https://bitovi.com/blog)
- [![Partnerships](https://www.bitovi.com/hubfs/Handshake-1.svg)
  
  PartnershipsLearn about Bitovi's technology partners
  
  ](https://www.bitovi.com/partnerships?hsLang=en-us)
- [![Academy](https://www.bitovi.com/hubfs/limbo/icons/icon-academy.svg)
  
  AcademyFree courses to build delivery skills
  
  ](https://www.bitovi.com/academy/?hsLang=en-us)
- [![Open source tools](https://www.bitovi.com/hubfs/icon%20-%20open%20source.svg)
  
  Open source toolsUse our tools or contribute to our open source mission.
  
  ](https://www.bitovi.com/open-source?hsLang=en-us)

Let's Connect

- [![Discord](https://www.bitovi.com/hubfs/DiscordLogo.svg)
  
  Discord
  
  ](https://discord.gg/J7ejFsZnJ4)
- [![LinkedIn](https://www.bitovi.com/hubfs/LinkedinLogo.svg)
  
  LinkedIn
  
  ](https://www.linkedin.com/company/bitovi/)
- [![GitHub](https://www.bitovi.com/hubfs/GithubLogo.svg)
  
  GitHub
  
  ](https://github.com/bitovi/)

![Eggbot](https://www.bitovi.com/hubfs/build_assets/bitovi-limbo-cms-react/338/js_client_assets/assets/eggbot-LTGhdSGL.png)

Name *

Work Email *

Phone

What's your project?

Send

### Contact Us

(312) 620-0386contact@bitovi.com

[Bitovi](https://www.bitovi.com/?hsLang=en-us)

- [Services](https://www.bitovi.com/services?hsLang=en-us)
- [Client Work](https://www.bitovi.com/client-work?hsLang=en-us)
- [Our Team](https://www.bitovi.com/about?hsLang=en-us)
- [Open Source](https://www.bitovi.com/open-source?hsLang=en-us)
- [Blog](https://www.bitovi.com/blog?hsLang=en-us)
- [Academy](https://www.bitovi.com/academy/?hsLang=en-us)

[Contact Us](https://www.bitovi.com/contact?hsLang=en-us)

- [ Advanced JavaScript ](https://www.bitovi.com/academy/learn-advanced-javascript.html?hsLang=en-us)
- [ DOM and jQuery ](https://www.bitovi.com/academy/learn-dom-jquery.html?hsLang=en-us)
- [ Debug JavaScript ](https://www.bitovi.com/academy/learn-to-debug-javascript.html?hsLang=en-us)
- [ Learn TypeScript ](https://www.bitovi.com/academy/learn-typescript.html?hsLang=en-us)
- [ Learn React ](https://www.bitovi.com/academy/learn-react-vite.html?hsLang=en-us)
- [ Learn Web Components ](https://www.bitovi.com/academy/learn-web-components.html?hsLang=en-us)
- [ Agile Program Management With Jira ](https://www.bitovi.com/academy/learn-agile-program-management-with-jira.html?hsLang=en-us)
- [ Learn RxJS ](https://www.bitovi.com/academy/learn-rxjs.html?hsLang=en-us)
- [ Giving a Training ](https://www.bitovi.com/academy/training.html?hsLang=en-us)
- [ Learn Technology Consulting ](https://www.bitovi.com/academy/learn-technology-consulting.html?hsLang=en-us)
- [ Learn React ](https://www.bitovi.com/academy/learn-react.html?hsLang=en-us) 
    - [ Setting Up Your Environment ](https://www.bitovi.com/academy/learn-react/setting-up-your-environment.html?hsLang=en-us)
    - [ Introduction to JSX ](https://www.bitovi.com/academy/learn-react/intro-to-jsx.html?hsLang=en-us)
    - [ What are React Components ](https://www.bitovi.com/academy/learn-react/components.html?hsLang=en-us)
    - [ Props: Component Arguments ](https://www.bitovi.com/academy/learn-react/props.html?hsLang=en-us)
    - [ Styling in React ](https://www.bitovi.com/academy/learn-react/styling-in-react.html?hsLang=en-us)
    - [ Stateful Hooks ](https://www.bitovi.com/academy/learn-react/stateful-hooks.html?hsLang=en-us)
    - [ Controlled vs Uncontrolled ](https://www.bitovi.com/academy/learn-react/controlled-vs-uncontrolled.html?hsLang=en-us)
    - [ Optimization Hooks ](https://www.bitovi.com/academy/learn-react/optimization-hooks.html?hsLang=en-us)
    - [ Managing Complex State ](https://www.bitovi.com/academy/learn-react/managing-complex-state.html?hsLang=en-us)
    - [ Context Hooks ](https://www.bitovi.com/academy/learn-react/context-hooks.html?hsLang=en-us)
- [ Learn NgRx ](https://www.bitovi.com/academy/learn-ngrx.html?hsLang=en-us)
- [ Learn Graphql ](https://www.bitovi.com/academy/learn-graphql.html?hsLang=en-us)
- [ Learn Docker ](https://www.bitovi.com/academy/learn-docker.html?hsLang=en-us)
- [ Learn CanJS ](https://www.bitovi.com/academy/learn-canjs.html?hsLang=en-us)
- [ Learn Angular ](https://www.bitovi.com/academy/learn-angular.html?hsLang=en-us)
- [ Advanced TypeScript ](https://www.bitovi.com/academy/advanced-typescript.html?hsLang=en-us)

[View More Courses](https://www.bitovi.com/academy/#courses) [ ]

# Optimization Hooks `page`

Learn how to optimize your React apps with `useMemo` and `useCallback`.

# Optimization Hooks

In addition to the core hooks exposed by React, namely `useState` and `useEffect`, there are several hooks aimed at optimizing your code for performance.

Specifically, optimization through memoization. In a nutshell, memoization is the process of caching the values returned from long-running functions, and returning the cached values when inputs are identical to the previous run.

There are two hooks which deal with memoization, `useMemo` and `useCallback`, let’s take a look at them below.

## useMemo

- Returns a memoized value.
- Recalculated synchronously based on declared dependencies.
- Used to optimize expensive calculations.

```
function Hello({ firstName, lastName }) {
  const name = React.useMemo(() => {
    // some expensive derived value
    return `${firstName} ${lastName}`;
  }, [firstName, lastName]);

  return <div>{name}</div>;
}

ReactDOM.render(
  <Hello firstName="Justin" lastName="Meyer" />,
  document.getElementById('root'),
);
```

In the code above, we’re utilizing `useMemo` to memoize a value derived from two props, `firstName` and `lastName`. (Imagine that in order to get the full `name`, we need to perform some long-running or expensive operation.)

Normally, we would perform this operation every time the component renders, regardless of the `firstName`/`lastName` prop values. When we memoize the value however, React keeps track of the inputs and outputs of this function, and caches inputs and output for the last time it was run. This means that if this component gets rendered with the same first and last name 100 times in a row, we’ll only need to perform the expensive operation once.

`useMemo` takes two arguments. The first is a function which performs the expensive operation and returns a value. The second is an array of dependencies. The dependency array determines which values, when changed, should cause the memoized value to be re-computed. All state values used in the function should be declared in the dependencies.

To sum it all up:

- When we need to do something expensive: 
    1. We wrap it in `useMemo`.
    2. Specify when it should re-compute.

### useMemo to cache a function call

Let’s take a look at a more real-world example. Here we’ll parse a large JSON object, then flatten it into more easily printable lines.

Here’s a look at it without `useMemo`:

```
function Hello({ bigJSONBlob }) {
  const data = JSON.parse(bigJSONBlob);
  const lines = flatten(data);

  return (
    <div>
      {lines.map((line) => (
        <div key={line}>{line}</div>
      ))}
    </div>
  );
}

function flatten(input) {
  return Object.keys(input)
    .map((key) => {
      if (typeof input[key] === 'object') {
        return [`${key}:`, ...flatten(input[key]).map((line) => `  - ${line}`)];
      }

      return [`${key}: ${input[key]}`];
    })
    .flat();
}

ReactDOM.render(
  <Hello bigJSONBlob={'{"hello": "world"}'} />,
  document.getElementById('root'),
);
```

This could get quite expensive for a large object, even the parsing could make a difference, so we memoize the whole value, only recalculating on `bigJSONBlob` changes. It uses `===` to detect changes and not a deep object comparison.

```
function Hello({ bigJSONBlob }) {
  const lines = React.useMemo(() => {
    const data = JSON.parse(bigJSONBlob);
    return flatten(data);
  }, [bigJSONBlob]);

  return (
    <div>
      {lines.map((line) => (
        <div key={line}>{line}</div>
      ))}
    </div>
  );
}

function flatten(input) {
  return Object.keys(input)
    .map((key) => {
      if (typeof input[key] === 'object') {
        return [`${key}:`, ...flatten(input[key]).map((line) => `  - ${line}`)];
      }

      return [`${key}: ${input[key]}`];
    })
    .flat();
}

ReactDOM.render(
  <Hello bigJSONBlob={'{"hello": "world"}'} />,
  document.getElementById('root'),
);
```

## useCallback

- A special case of useMemo that returns a function instead of a value.
- `useCallback(fn, deps)` is equivalent to `useMemo(() => fn, deps)`
- Used to maintain referential equality between renders.

[`useCallback`](https://reactjs.org/docs/hooks-reference.html#usecallback) is particularly useful when defining event handlers. In such cases, we’re not necessarily interested in memoizing a single value, but rather in memoizing a callback function. This is very common in React, as we frequently use callbacks as props.

Below is a clickable `Hello` component which defines an un-memoized `handleClick` function.

```
function Hello({ firstName, lastName }) {
  const handleClick = () => {
    console.log(`${firstName} ${lastName}`);
  };

  return <button onClick={handleClick}>Hello</button>;
}

ReactDOM.render(
  <Hello firstName="Justin" lastName="Meyer" />,
  document.getElementById('root'),
);
```

Now below, we’ll wrap `handleClick`’s logic in a `useCallback` so we can cache the results.

```
function Hello({ firstName, lastName }) {
  const handleClick = React.useCallback(() => {
    console.log(`${firstName} ${lastName}`);
  }, [firstName, lastName]);

  return <button onClick={handleClick}>Hello</button>;
}

ReactDOM.render(
  <Hello firstName="Justin" lastName="Meyer" />,
  document.getElementById('root'),
);
```

## Exercise

Let’s use our optimization hooks knowledge to make our Tic-Tac-Toe game a bit more performant!

### The problem

✏️ Modify the `Board` component so that it’s `handleSquareClick` function uses the `useCallback` hook.

```
const squareStyling = {
  width: '200px',
  height: '200px',
  border: '1px solid black',
  boxSizing: 'border-box',
  display: 'flex',
  justifyContent: 'center',
  alignItems: 'center',
  fontSize: '6em',
  color: 'black',
};

const boardStyling = {
  display: 'flex',
  flexWrap: 'wrap',
  flexDirection: 'row',
  justifyContent: 'flex-start',
  width: '600px',
  height: '600px',
  boxShadow: '0px 3px 8px 0 rgba(0, 0, 0, 0.1)',
  boxSizing: 'border-box',
};

function Square({ onClick, symbol, id }) {
  return (
    <div id={id} onClick={onClick} style={squareStyling}>
      {symbol}
    </div>
  );
}

function Board() {
  const [board, setBoard] = React.useState([
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
  ]);
  const [isXTurn, setIsXTurn] = React.useState(true);

  function handleSquareClick(squareIndex) {
    if (board[squareIndex]) {
      return;
    }

    const newBoard = [...board];
    newBoard[squareIndex] = isXTurn ? 'X' : 'O';

    setBoard(newBoard);
    setIsXTurn((value) => !value);
  }

  return (
    <div style={boardStyling}>
      {board.map((symbol, index) => (
        <Square
          key={index}
          symbol={symbol}
          onClick={() => handleSquareClick(index)}
        />
      ))}
    </div>
  );
}

ReactDOM.render(<Board />, document.getElementById('root'));
```

## Solution

 Click to see the solution

```
const squareStyling = {
  width: '200px',
  height: '200px',
  border: '1px solid black',
  boxSizing: 'border-box',
  display: 'flex',
  justifyContent: 'center',
  alignItems: 'center',
  fontSize: '6em',
  color: 'black',
};

const boardStyling = {
  display: 'flex',
  flexWrap: 'wrap',
  flexDirection: 'row',
  justifyContent: 'flex-start',
  width: '600px',
  height: '600px',
  boxShadow: '0px 3px 8px 0 rgba(0, 0, 0, 0.1)',
  boxSizing: 'border-box',
};

function Square({ onClick, symbol, id }) {
  return (
    <div id={id} onClick={onClick} style={squareStyling}>
      {symbol}
    </div>
  );
}

function Board() {
  const [board, setBoard] = React.useState([
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
    '',
  ]);
  const [isXTurn, setIsXTurn] = React.useState(true);

  const handleSquareClick = React.useCallback(
    (squareIndex) => {
      if (board[squareIndex]) {
        return;
      }

      const newBoard = [...board];
      newBoard[squareIndex] = isXTurn ? 'X' : 'O';

      setBoard(newBoard);
      setIsXTurn((value) => !value);
    },
    [board, isXTurn],
  );

  return (
    <div style={boardStyling}>
      {board.map((symbol, index) => (
        <Square
          key={index}
          symbol={symbol}
          onClick={() => handleSquareClick(index)}
        />
      ))}
    </div>
  );
}

ReactDOM.render(<Board />, document.getElementById('root'));
```

## Next steps

✏️ Head over to the [next lesson](https://www.bitovi.com/academy/learn-react/managing-complex-state.html?hsLang=en-us) to get a more comprehensive example on how one can use state.

###### On this page...

###### Get help

If you need [help](https://discord.gg/J7ejFsZnJ4) with an exercise, please reach out to us on [Discord](https://discord.gg/J7ejFsZnJ4)

If you find a bug, please [create an issue](https://github.com/bitovi/academy/issues/new) or email [contact@bitovi.com](mailto:contact@bitovi.com?Subject=Training%20Suggestion)

## Join the Bitovi Newsletter

 Do you want to receive updates about new Bitovi Academy courses, Bitovi open source projects, and dev community news? If so, please provide your email. We won’t spam you or give it away for any reason!  
*By providing your email you agree to receive communications from Bitovi*

![](https://bitovi.github.io/academy/static/img/close.svg)

```json
{
     "@context": "http://schema.org",
     "@type": "Organization",
     "mainEntityOfPage":{
          "@type":"WebPage",
          "@id":"https://www.bitovi.com/academy/learn-react/optimization-hooks.html",
          "description": "Learn how to optimize your React apps with `useMemo` and `useCallback`. 
"
     },
     "url": "http://bitovi.com",
     "logo": "https://www.bitovi.com/hubfs/bitovi-logo-23-1.svg",
     "image": "https://www.bitovi.com/hubfs/bitovi-logo-x2.png",
     "name": "Bitovi Web App Consulting",
     "alternateName": "Bitovi",
      "naics": "541511",
      "description": "Bitovi is a UX, UI design and front-end JavaScript development consulting company",
     "address": {
          "@type": "PostalAddress",
          "streetAddress": "1134 Pine Tree Lane ",
          "addressLocality": "Libertyville",
          "addressRegion": "IL",
          "addressCountry": "United States",
          "postalCode": "60048"
     },
     "areaServed": {
          "@type": "GeoCircle",
          "geoMidpoint": {
               "@type": "GeoCoordinates",
               "latitude": "41.8781",
               "longitude": "87.6298"
          },
          "geoRadius": "5000 km"
     },
     "telephone": "312-620-0386",
     "email": "contact@bitovi.com",
     "sameAs": [
          "https://www.facebook.com/BitoviLLC/",
          "https://twitter.com/bitovi",
          "https://www.linkedin.com/company/bitovi"
     ]
}
```