Improving React App's performance

Improving React App's performance

Optimizing application performance is key for developers who are mindful of keeping a user’s experience positive to keep them on an app and engaged. React doesn’t promise magical performance gains, but it provides just the right tools and functionalities to make it easy. In this article, we will discuss some of the methods React provides that we can use to improve the performance of the app.

Code Splitting

Since all the code of a React app gets bundled into a single file using tools like webpack, the bundle size could be huge as the app grows, especially if it uses multiple 3rd party libraries. This could affect the initial load time of the app since the browser runs the whole bundle file before loading the app. To counter this, we can split the bundle into many parts and load them only when they are needed. This can be achieved by dynamic imports or 'lazy loading'. React provides a function to do so:

React.lazy

It is a new function in react that lets you load React components dynamically through code splitting without help from any additional libraries.

Before:

import OtherComponent from './OtherComponent';

After:

const OtherComponent = React.lazy(() => import('./OtherComponent'));

when webpack comes across this syntax, it will automatically start code splitting the app, thus reducing bundle size. Lazy loading helps reduce the risk of web app performance to a minimum.

useMemo or useCallback

Sometimes in your app, a CPU-Expensive function gets called repeatedly due to re-renders of a component, which can lead to slow rendering. One way to limit this is by using memoized functions or values. React provides two hooks called useMemo and useCallback which are quite similar with a same purpose, to eradicate unnecessary calls to expensive functions.

  • useMemo - takes a callback function and runs it only when any of its dependencies change and thus returns a memoized value.
    • Syntax:
      const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
      
  • useCallback - takes a callback function and returns a memoized version of the callback that only changes if one of the dependencies has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g. shouldComponentUpdate).
    • Syntax:
      const memoizedCallback = useCallback(
      () => {
      doSomething(a, b);
      },
      [a, b],
      );
      

React.PureComponent or React.memo

Whenever a component re-renders, its child components also get re-rendered, regardless of whether or not their props or states have changed or not, thus increasing the burden on the CPU and slowing down the app performance. React has a solution for that as well, named PureComponents and memo:

  • React.PureComponent - Instead of using the simple React.Component, we can use React.PureComponent to reduce the re-renders of a component unnecessarily. The difference between them is React.Component doesn't implement shouldComponentUpdate(), but React.PureComponent implements it with a shallow prop & state comparison.
  • React.memo - The functional component equivalent of that is React.memo, a Higher order functional component that takes a component and returns another component that will only be re-rendered whenever its states or props change and not on every re-render of its parent.

Maintaining State Colocation

This is a process of moving the state as close to where it is needed, as possible. Sometimes in React app, we have a lot of unnecessary states inside the parent component which makes the code less readable and harder to maintain. Not to forget, having many states inside a single component leads to unnecessary re-renders for the component. It is better to shift states which are less valuable to the parent component, to a separate component.

These were some of the ways we can improve a React app's performance. But remember, excess of anything is bad, too much optimization can be counterproductive as well, so use them only when you have huge performance issues in your app. Thank you for reading!!