Properly understand Hooks to improve your application performance
Tags: webdev, react, performance
Published: 2022-11-04 17:37:30

When developing a product with React, if you write components and use Hooks a lot without paying special attention, the overall operation may become slow, even if the project size is not large.

It's important to understand the role of Hooks and to use them in the right places. In this article, we summarize the explanations of some of the Hooks provided by React.

## :pushpin: useMemo
`useMemo` is a hook to save (memoize) the result of a function and retrieve the value when it is called again. This eliminates unnecessary recalculation and improves performance.

```tsx
const value = useMemo(() => {
  // doSomething
}, [])
```

It's effective when used for functions with high computational cost. Also, unlike `useCallback`, it is not a Hook that memoizes the function itself. Also, by passing variables as the second argument (deps), the function can be called to recalculate when thosae values are changed.

:-1: The following code calls a function each time a component is rendered.

```tsx
const Component = () => {
  const doSomething = () => {
    // A function with a with high computational cost
  }

  return (
    <div>{doSomething()}</div>
  )
}
```

:+1: The following code calls the function only when the component is rendered for the first time or when the value passed to deps is updated.

```tsx
import { useMemo } from 'react'

const Component = () => {
  const doSomething = useMemo(() => {
    // A function with a with high computational cost
  }, [])

  return (
    <div>{doSomething}</div>
  )
}
```

## :pushpin: useCallback
`useCallback` memoizes the function itself. It is mainly used for functions defined inside components such as handlers.

All functions defined inside a component are regenerated when the component is re-rendered (e.g., when the props value is updated or the parent component is re-rendered).

Basically, there is no need to regenerate functions on every rendering pass, so the use of `useCallback` improves performance.

### :zap: Example

For example, suppose you have the following code In this code, re-rendering of the Child component will occur at the following times:

* When setValue is called by some action
* When someData is updated by some action

Assuming that this action can occur frequently, each time this happens, the old function is discarded and a new function is created and bound to the button. The accumulation of such components will needlessly degrade performance.

```tsx
const Parent = () => {
  const [value, setValue] = useState(0)

  return (
    <>
      <div>{value}</div>
      <Child data={someData} />
    </>
  )
}

const Child = (props) => {
  const handleClick = () => {
    // doSomething
  }

  return (
    <>
      <div>{props.data}</div>
      <button onClick={handleClick}></button>
    </>
  )
}
```

In this case, you can wrap the handleClick function with `useCallback`.

```tsx
import { useCallback } from 'react'

// ...

const Child = (props) => {
  const handleClick = useCallback(() => {
    // doSomething
  })

  // ...
}
```

### :zap: React.memo

In addition, re-rendering of child components, which occurs when rendering parent components, can be avoided by using `React.memo`.

```tsx
import { memo } from 'react'

// ...

const Child = memo((props) => {
  // ...
})
```

Components wrapped in `React.memo` will return memoized values as long as the props do not change. This reduces unnecessary re-rendering.