React Performance with useMemo

Explanation of useMemo and how to use useMemo in component


In this article you'll understand useMemo() and learn how to improve your react application's performance.

Sometimes, React must do expensive calculations, such as filtering massive amounts of data or running billions of cycles, which might cause React applications to render slowly. 

This is where useMemo hook comes in handy, which is used to optimize react applications.

useMemo

The useMemo is another essential built-in hook in React that comes in handy when we create a production-ready React application. The primary reason to use useMemo in our components is for better performance.

Technically, useMemo caches results and saves the output of calculations between renderings. As a result, you can expedite the application by avoiding recalculation when the component is loaded.

Unnecessary Calculations

Suppose I've built a React application that renders a set of tabs and when I switch tabs it updates the UI with their corresponding content and I also I’ve an input field.

import TabBtn from "./TabBtn"
function App() {
  const [activeTab, setActiveTab] = useState('all')
  const [newTask, setNewTask] = useState('')
  
  const handleClick = (tabName) => {
    setActiveTab(tabName)
  }
  const handleNewTaskChange = (e) => {
    setNewTask(e.target.value)
  }
  return (
    <section className="tasks">
      <label>New Task</label>
      <input value={newTask} type="text" onChange={handleNewTaskChange} />
      <menu>
        <TabBtn onClick={() => handleClick('all')} activeId={activeTab === 'all'}>All</TabBtn>
        <TabBtn onClick={() => handleClick('completed')} activeId={activeTab === 'completed'}>Completed</TabBtn>
        <TabBtn onClick={() => handleClick('active')} activeId={activeTab === 'active'}>Active</TabBtn>
      </menu>
      <ul>
        {activeTab === 'all' && <li>All Tasks</li>}
        {activeTab === 'completed' && <li>Completed Tasks</li>}
        {activeTab === 'active' && <li>Active Tasks</li>}
      </ul>
    </section>
  )
}

To choose a tab and bind an input field, I used the useState hook. The component is going to re-render the application when the state changes or updates.

I've got another file named utils.js. This file contains a function called utils and this utils function performs expensive operations.

// utils.js
export const utils = () => {
  let tasks = [];
  for (let i = 0; i < 1000000; i++) {
    tasks.push({
      id: i + 1
    });
  }
  return tasks;
}

Now let's call utils function inside the App so I can artificially slow down my application.

// App.js
const expensiveCalculation = utils()

In the browser when you switch tabs you'll see it taking a small pause during rendering and also when you type into the input field it takes a while before the letter shows up.

As previously stated, React evaluates applications when state, props, and context change so each keystroke causes the state to update and re-render the component, and that will again cause the utils function to re-calculate the count or cycle through the loop over a million times before it settles. It would happen every time, even if the function produced the same result.

Here comes another essential hook useMemo() to optimize React application.

We use useMemo hook to memoize the output of a function. Instead of recalculating the result each time the components re-render, It stores the results of expensive functions and returns cached results.

How to use useMemo()

The useMemo hook accepts callback function and returns result of a function. As second argument, it takes its dependency and if calculation function has no dependency you can pass an empty array i.e. []

useMemo(() => {}, [])

To use useMemo() import it at the top of component.

import { useMemo() } from 'react 

Now we can wrap utils function with useMemo.
const expensiveCalculation = useMemo(() => utils(), [])

Now switch tabs and type into input fields; you’ll see application is fast.

Because of useMemo(), the expensiveCalculaition variable is now memoized, which guarantees that the utils function is only called once during initial rendering. This means that after the component renders for the first time, it won't recalculate until the dependencies change, and since there are no dependencies, the function won't re-execute.

Let's say that if I type anything in the input field, I want to call the utils method once again. I'll provide the newTask variable as a dependency.

const expensiveCalculation = useMemo(() => utils(), [newTask])

Now  React compares the current and previous dependencies; if a change occurs, then utils function will execute the calculation. Switching tabs is fine.

Don't overuse useMemo

Memorization can increase React performance, however it is best to avoid using useMemo while performing inexpensive operations. React will go out of its way to compare it on each execution, causing React to perform more work.

Additionally, if the computation changes or updates often, we don't want this behavior to occur. Before implementing memorizing in your application, I would advise you to thoroughly profile your component and evaluate various optimizations.

Conclusion

useMemo is a built-in React hook used for optimizing the performance of an application. useMemo memoize expensive calculations to skip recalculation. 

When it comes to performance issues useMemo() is one of the best options you can apply in react application. With the useMemo hook, you can store the result of a calculation or catch computation value and use it across multiple renderings.

0 Comments:

Post a Comment