React performance optimization with useMemo & memo
Tags: react, webdev, javascript, tutorial
Published: 2020-05-05 05:54:34

In this article, I will provide a set of techniques to optimize child components re-rendering. There are many circumstances of unnecessary component re-rendering. Usually, it happens because of the parent component inside which the state changes.


Firstly we should note:
>any manipulation with component state leads to re-rendering of entire components tree in spite of the interaction with parent component state.

In case your app is small, without heavy components - additional re-rendering is bearable. It doesn't affect app performance so much. The bigger app and individual components inside it - the more noticeable effects of unnecessary re-rendering are. It leads to processes delay and increasing of loads on all components.

Here is the example of such re-rendering. To track the re-rendering I left <code>console.log</code> in the render of each internal component. The number of the re-rendered element will be displayed in the console.
####---FormContainer####
####------ItemComponent1 (console.log)####
####---------ItemComponent2 (console.log)####
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/bto1tu7pndh2aqj5rqns.gif)
###__There are several options to solve this problem:__###
####__№1 - useMemo__####
This hook is mainly designed to optimize calculations. The calculation restarts if the dependencies specified as a second argument changed. Thus, the load on the component reduce.

<code>useMemo</code> is also applicable to components, returning them persisted. It works if the dependencies do not change during the component 's lifecycle. In case we don't specify dependencies (leave an empty array) - the component remains, as it was at the time of initialization. All the passed parameters remain closed in the initial state.
```jsx
import React from 'react'

  // local variables
  const FIELD_NAMES = {
    FIRST_NAME: 'firstName',
    LAST_NAME: 'lastName'
  }
  
  const FormContainer = () => {
    const [formValues, changeFormValues] = React.useState({
      [FIELD_NAMES.FIRST_NAME]: '',
      [FIELD_NAMES.LAST_NAME]: ''
    })
  
    const handleInputChange = fieldName => e => {
      const fieldValue = e.target.value
  
      changeFormValues(prevState => ({
        ...prevState,
        [fieldName]: fieldValue
      }))
    }
  
    return (
      <div>
        <input
          type='text'
          onChange={handleInputChange(FIELD_NAMES.FIRST_NAME)}
          name={FIELD_NAMES.FIRST_NAME}
          value={formValues[FIELD_NAMES.FIRST_NAME]}
        />
        <input
          type='text'
          onChange={handleInputChange(FIELD_NAMES.LAST_NAME)}
          name={FIELD_NAMES.LAST_NAME}
          value={formValues[FIELD_NAMES.LAST_NAME]}
        />
  
        <ItemComponent1 />
      </div>
    )
  }
  
  const ItemComponent1 = () => {
    console.log('ITEM 1 RENDERED')
  
    return React.useMemo(
      () => (
        <div>
          <span>Item 1 component</span>
          <ItemComponent2 />
        </div>
      ),
      []
    )
  }
  
  const ItemComponent2 = () => {
    console.log('ITEM 2 RENDERED')
  
    return <div>Item 2 component</div>
  }
```
In the example above, we used <code>useMemo</code> inside <code>ItemComponent1</code>. Thus anything returns the component will be initialized only once. It won't be re-rendered at the time of parent re-rendering.

Below you can see the result of how hook works:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/cng9v4mugoa9zscu74or.gif)
As you see, when the state changes inside the <code>FormContainer</code>, the <code>useMemo</code> does not allow component <code>ItemComponent1</code> to re-render.
One more thing. Let's assume we specified <code>firstName</code> as a dependency passed via props from the parent. In this case, the component will be re-rendered only if <code>firstName</code> value changes.
####__№2 - memo__####
You can reach the same effect using a high order component (<code>HOC</code>) named <code>memo</code>. If you don’t want the component <code>ItemComponent2</code> involved in re-rendering - wrap it in <code>memo</code>. Here we go:
```jsx
const ItemComponent2 = React.memo(() => {
  console.log('ITEM 2 RENDERED')
  
  return <div>Item 2 component</div>
})
```
If we pass props to a component wrapped in a <code>HOC memo</code>, we will be able to control the re-rendering of that component when the prop changes. To do this we should pass as a second argument a function  which:
1. Compares the props values before and after the change (<code>prevProps</code> and <code>nextProps</code>)
2. Returns a boolean value upon which React will understand whether to re-rendered the component or no.
```jsx
  const ItemComponent1 = ({ firstNameValue, lastNameValue }) => {
    console.log('ITEM 1 RENDERED')
  
    return (
      <div>
        <span>Item 1 component</span>
        <ItemComponent2
         firstNameValue={firstNameValue}
         lastNameValue={lastNameValue}
        />
      </div>
    )
  }
  
  const ItemComponent2 = React.memo(
    () => {
      console.log('ITEM 2 RENDERED')
  
      return <div>Item 2 component</div>
    },
    (prevProps, nextProps) =>
      prevProps.firstNameValue !== nextProps.firstNameValue
  )  
```
In this example above we compare old <code>firstName</code> and new props state. If they are equal the component will not be re-rendered. Hereby we ignore the <code>lastName</code> on which change the <code>firstName</code> will have the same value all the time. That is why the component will not be re-rendered.

You can see the result below:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/zpbkgtr4ywh9b96u6mlq.gif)
>React controls the second argument by default. This means comparing of the props value only to primitive types and one nested level. Props as <code>objects, functions, or arrays</code> will cause component re-render. You can control such moments describing needed comparison in the function. The function should passed as a second argument.

Another hooks tutorials:
[<code>useState</code>](https://dev.to/max_frolov_/react-hooks-usestate-rules-and-tips-for-component-state-manipulation-1gd6) [<code>useReducer</code>](https://dev.to/max_frolov_/react-hooks-usereducer-complex-state-handling-243k)

More tips and best practices on my [twitter](https://twitter.com/max_frolov_).

Feedback is appreciated. Cheers!