Top React Performance Optimization Tips in 2022

By Saurabh Barot   |   19 January, 2022
Top React Performance Optimization Tips in 2022

Quick Summary:

Performance issues in web apps are nothing new, and developers have dealt with these difficulties for quite some time. This is why developers are certain to run into performance concerns whenever a new language is created. One such programming language is React. It has a quick DOM, and it’s fast to the point where it sometimes renders the tree with a lot of useless components. This causes a UI issue, and developers may be unwilling to continue using the language as a result. However, there are various methods for React Performance Optimization.

Before releasing a React app, Dedicated React Developer team should at the very least examine its performance and look for ways to improve the app’s end-user experience. Internally, React employs several innovative approaches to reduce time-consuming DOM transactions required to refresh the user interface. For many applications, utilizing React will result in a fast user experience without requiring extensive performance optimization.

When creating a react application, a lot of thinking goes into how the app should function and look. At the very least, any team or professional developer should examine the app’s performance and search for ways to improve the end-user experience. This step is frequently overlooked, but this post will discuss react optimization techniques for improved performance.

React is a user interface library written in JavaScript. React comes with several options for reducing the number of time-consuming DOM operations required to refresh the UI. For many applications, utilizing React will result in a fast user experience without requiring extensive performance optimization. However, there are several strategies to improve react performance.

Let’s take a look at some of the techniques for optimizing react performance

Techniques for optimizing react

Use React. Fragment To Avoid Adding Extra Nodes to the Dom

With React, there are cases where you will need to render multiple elements or return a group of related items. Let’s look at the example.

function App() {
  return (
    <div>
      <h1>Hello React!</h1>
      <h1>Hello React Again!</h1>
    </div>
  );
}

The above code will give you an error stating ” Adjacent JSX elements must be wrapped in an enclosing tag”.  This means that you need to wrap both elements within the parent div.

This will solve the error, but it comes with the risk. Here an extra node is added to the DOM. In a case, like this where a child component is enclosed within the parent component, it creates an issue.

The better way of solving this issue is to use React Fragment which will not add additional nodes to the DOM


function Columns()
 {
  return (
    <React.Fragment>
      <td>Hello React!</td>
      <td>Hello React Again!</td>
    </React.Fragment>
  );
}

You can also use short syntax <></> for declaring fragment.

function Columns()
 
{
  return (
    <>
      <td>Hello React!</td>
      <td>Hello React Again!</td>
    </>
  );
}

Use React. Suspense and React.Lazy for Lazy Loading Components

Lazy loading is a great technique for react performance improvements. The basic idea of lazy loading is to load the component when it’s needed. React comes bundled with React. Lazy API so that you can render a dynamic import as a regular component.  Here instead of loading your regular component like :

import LazyComponent from './LazyComponent';

You can cut down the risk by using the lazy method to render the component

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

React. Lazy takes a function that must call a dynamic import(). This will return a promise which resolves to a module with default export containing a react component

The lazy component should be rendered inside a suspense component, which allows you to add fallback content as a loading state while waiting for the lazy component to load.


import React, { Suspense } from 'react';

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

function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading....</div>}>
<LazyComponent />
</Suspense>
</div>
);
}

Use Production Build

While doing react performance testing, make sure you’re testing with the minified production build if you’re benchmarking or having reacted performance issues.

React comes with many useful warnings by default, and these alerts are useful in the development process. However, they make React bigger and slower, so make sure you use the production version when deploying the project.

If you’re not sure if your build process is set up correctly, you can use React Developer Tools for Chrome to check. The icon will have a dark background if you visit a site that uses React in production mode:

react.js web app

The icon will have a red backdrop if you visit a site that is using React in development mode:

React.js

When working on your app, you should use the development mode, and when releasing it to users, you should use the production model. It’s also worth noting that if you’re utilizing React via a CDN, you should update React from development files to production-ready versions.

<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script><script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

Use React. memo for component Memoization

React. Memo is a great way of react js performance optimization as it helps functional cache components.

Memoization is a technique for speeding up computer programs by caching the results of expensive function calls and returning the cached result when the identical inputs are encountered again.

So how does it works? When a function is rendered using this technique, it will save the result in memory, and the next time the function with the same argument is called, it provides the saved result-saving bandwidth.

In React, functions are functional components, and arguments are props. Let’s understand it better with an example. So, how does it function? When a function is rendered using this technique, the result is preserved in memory, and the saved result is returned the next time the function with the same parameter is invoked, conserving bandwidth.

Arguments are props in React, while functions are functional components. Let’s look at an example to help us grasp it better.

import React from 'react';
const MyComponent = React.memo(props => {
/* render only if the props changed */
});

React. Memo is a higher-order component, and it’s similar to React. Pure component but for using function components instead of classes.

Flat list Optimization React Native Using React-Window

This reacts performance tuning technique is used to render a large list of data or a table with enormous data, and it can significantly slow down your app’s performance. Virtualization can help in such scenarios like this with the help of libraries like react-windows. It helps solve this problem by rendering only currently visible items in the list, which allows the rendering of lists of any size.


import React from 'react';
import { FixedSizeList as List } from 'react-window';
import './style.css';

const Row = ({ index, style }) => (
<div className={index % 2 ? 'ListItemOdd' : 'ListItemEven'} style={style}>
Row {index}
</div>
);
const Example = () => (
<List
className="List"
height={150}
itemCount={1000}
itemSize={35}
width={300}
>
{Row}
</List>
);

Using Production Mode Flag in Webpack

This reacts performance optimization technique is useful for using webpack 4 as a module bundler for the app. You can consider setting the mode option to production. This tells webpack to use built-in  optimization:


module.exports = {

mode: 'production'

};

You can pass it as a CLI argument.

webpack --mode=production

Doing this will limit optimizations, such as minification or removing development-only code to libraries. It will not expose source code, file paths, and much more.

Multiple Chunk Files

Your application will always start with a few elements. You can quickly add new features and dependencies to your system. It’ll result in a massive production file. Consider utilizing CommonsChunkplugin for webpack to segregate your vendor or third-party library code from your application code, resulting in two different files. Vendor.bundle.js and app.bundle.js are the two files you’ll end up with. The browser caches these files less frequently and retrieves resources in parallel, reducing load time.

Avoid Inline Function Definition in the Render Function

The inline function will always fail the prop diff when React conducts a diff check since functions are objects in JavaScript ( {} ! = {} ). Also, if an array function is used in a JSX property, it will produce a new function instance on each render. The garbage collector may have a lot of work on his hands as a result of this.


Default class CommentList extends React.Component {

state = {

comments: [],

selected commented: null

}

render(){

const { comments } = this.state;

return (

comments.map((comment)=>{

return <Comment onClick={(e)=>{

this.setState({selectedCommentId:comment.commentId})

}} comment={comment} key={comment.id}/>

})

)

}

}

Instead of defining the inline function for props, you can define the arrow function


default class CommentList extends React.Component {

state = {

comments: [],

selectedCommentId: null

}

onCommentClick = (commentId)=>{

this.setState({selectedCommentId:commentId})

}

render(){

const { comments } = this.state;

return (

comments.map((comment)=>{

return <Comment onClick={this.onCommentClick}

comment={comment} key={comment.id}/>

})

)

}

}

Dependency Optimization

It’s good to analyze how much code you’re using from dependencies while optimizing react app bundle size. You may, for example, be using Moment.js, which offers multi-language localized files. If you don’t need to support several languages, you can remove unnecessary locales from the final bundle with the moment-locales-webpack-plugin.

Let’s take the case of loadash, where you’re only using 20 of the 100+ methods available. Having all those other approaches isn’t ideal in that case. You may do this by removing unneeded functions with the loadash-webpack-plugin.

From here, you can download the list of dependencies you can optimize.

LookinG for React developers to hire?

Get in touch to develop highly scalable web app project.

Throttling and Debouncing Event Action in JavaScript

The number of times an event handler is invoked in a particular time limit is known as the trigger rate. Mouse clicks, on average, have lower event trigger rates than scrolling and mouseover. Higher event trigger rates can cause your program to crash, but there are workarounds.

Determine which event handler is performing the costly work. An XHR request or DOM manipulation that produces UI modifications, for example, processes a lot of data or a calculation event task. Throttling and debouncing strategies can help in these situations without requiring any changes to the event listener.

Throttling

In essence, throttle involves postponing the execution of a function. When an event is triggered, you’ll add a few milliseconds of delay instead of instantly executing the event handler/function. When implementing infinite scrolling, this can be used. You can, for example, defer the XHR call rather than fetching the next result set as the user scrolls.

Throttling can be done in a variety of ways. You can set a limit based on the number of triggered events or the delay event handler that is being used.

Debouncing

Debouncing is a strategy for preventing the event trigger from firing too frequently. If you’re using Lodash, you can use the debounce function to wrap the function you want.

Let’s use an example to grasp this better.


Import debouce from 'lodash.debounce';

class SearchComments extends React.Component {

constructor(props) {

super(props);

this.state = { searchQuery: “” };

}

setSearchQuery = debounce(e => {

this.setState({ searchQuery: e.target.value });

// Fire API call or Comments manipulation on client end side

}, 1000);

render() {

return (

<div>

<h1>Search Comments</h1>

<input type="text" onChange={this.setSearchQuery} />

</div>

);

}

}

If you’re not using loadash, you can use the minified debounced function to implement in javascript.

Function debounce(a,b,c){var d,e;return function(){function h(){d=null,c||(e=a.apply(f,g))}var f=this,g=arguments;return clearTimeout(d),d=setTimeout(h,b),c&&!d&&(e=a.apply(f,g)),e}}

Avoid Async Initialization in componentWillMount()

Only one time, immediately before the initial render, is componentWillMount() invoked. Because this function is run before render, our component will not access the references or DOM element ().

Here’s a terrible example:


function componentWillMount() {

axios.get(`api/comments`)

.then((result) => {

const comments = result.data

this.setState({

comments: comments

})

})

}

Make component initialization async in the componentDid Mount lifecycle hook to improve it:


function componentDidMount() {

axios.get(`api/comments`)

.then((result) => {

const comments = result.data

this.setState({

comments: comments

})

})

}

Because props and state are defined during this lifecycle method, WillMount() is useful for handling component setups and doing synchronous calculations based on props.

Avoid using Index as Key for map

While performing performance optimization in react, you often see an index as a key when rendering a list.


{

comments.map((comment, index) => {

<Comment

{..comment}

key={index} />

})

}

Using the key as the index, on the other hand, may cause your app to display erroneous data because the key is used to identify DOM elements. When you push or delete an item from the list, React considers that the DOM element represents the same component as before if the key is the same.

Although it’s typically preferable to use a unique attribute as a key, you can use the shortid module to generate one if your data lacks one.


import shortid from  "shortid";

{

comments.map((comment, index) => {

<Comment

{..comment}

key={shortid.generate()} />

})

}

However, if you have unique property, such as an ID, it's better to use that.

{

comments.map((comment, index) => {

<Comment

{..comment}

key={comment.id} />

})

}

In the following cases, it’s okay to use the index as the key:

  • The items and list are both static.
  • There are no IDs on the items in the list, and they will never be reordered or filtered.
  • The list is unchangeable.

Use CSS Animation instead of JS Animation

Animations are inevitable for fluid and pleasurable user experiences. There are many ways to implement web animations. Generally, animations are created in three ways:

  • CSS Transitions
  • CSS animations
  • Javascript

Which one is chosen depends on the type of animation we want to add.

When to use CSS -based animation

CSS based Animation

  • To add “one-shot” transitions like toggling UI elements state
  • For smaller, self-contained states of UI elements

When to use JavaScript-Based animation

JavaScript Based Animation

  • When you want to have advanced effects
  • It would help if you had significant control over the animation
  • Need to trigger animation, like mouseover, etc
  • When using requestAnimationFrame for visual changes

Enable Gzip Compression on Web Server

The web server can reduce the file size by using Gzip compression, which means your website will load faster. Because JavaScript, CSS, and HTML files include a lot of repeating text with many whitespaces, gzip works exceptionally well. Because gzip compresses common strings, it can reduce the size of pages and stylesheets by up to 70%, resulting in faster initial rendering.

If you are using Node/Express as the backend, you can use Gzipping to compress your bundle size with the compression module.


const express = require('express');

const compression = require('compression');

const app = express();

// Pass `compression` as a middleware!

app.use(compression());

Using a CDN

A CDN is a terrific way to swiftly and efficiently provide static information from your website or mobile application to your audience. The “edge server” is the closest user request server, depending on the geolocation. The user is connected to the edge server when they request material from your website, supplied through a CDN, and they are guaranteed the best online experience. These are some of the most effective CDN providers on the market. CloudFront, CloudFare, Akamai, MAXCDN, Google Cloud CDN, and others are examples.

You can also host your static content on CDN using Nelilfy or Sugre. sh. Surge is a free CLI tool that automatically deploys your static project to a high-performance CDN.

Now that we have seen some of the react performance tips. Let’s take a look at some of the best practices to improve react performance.

Also Check – Pros and Cons of ReactJS Web Application Development

React Performance Best Practices

Let’s look at some of the best practices to keep in mind for react app performance optimization.

React Performance Best Practices

Component Interaction

Using excellent tools like React dev tools, you can solve more than 50% of react performance issues in React by examining how your components interacted in your project. However, before figuring out how the components behave, make sure you understand how React works underneath the hood.

Lazy Loading

To keep ahead of the game of speed, it’s best only to load the resources you’ll need right away. Prioritize the resources that must be loaded first and use techniques like code-splitting to load the balance of the code or resources afterward.

Trim JavaScript Bundles

To reduce any code redundancy, audit and trim JavaScript packages. When you’re duplicating things unnecessarily or accidentally, the possibilities are increased. Ensure that they are analyzed and that the amount of your bundled code is determined.

Server-Side Rendering (SSR)

If you’re worried about SEO other than Google, consider whether SSR is truly necessary. SSR isn’t as complicated as it appears. If not done correctly, it can wreak havoc on your app’s performance, possibly leading to disaster.

RESELECT & Immutable.js

If you’re having trouble with performance in Redux-based React projects, try RESELECT and Immutable.js. Reselect is a basic Redux selector library that may be used to create memorized selectors. Selectors can be defined as functions that retrieve chunks of the Redux state for React components.

Wrapping Up!

There are various react optimization techniques to improve react performance, such as lazy loading components, avoiding unnecessary renders, and much more. To make the most of the react app, you need to leverage its tools and techniques. A react web app performance lies in the simplicity of its components, and overwhelming the render-diff algorithm can make your app perform poorly and frustratingly. The techniques outlined above are all great ways for you to practice react js performance optimization for your application.

have a unique app Idea?

Hire Certified Developers To Build Robust Feature, Rich App And Websites.

Get in Touch!

Saurabh Barot

Saurabh Barot is co-founder and Experienced Chief Technology Officer at Aglowid IT Solutions. His deep industry experience in Angular, React, Ruby on Rails, PHP, Mean Stack and just to name few, has helped the company reach to a new level. He believes that technology is all about exploring new possibilities. Whatever a mind can think (exception can't be ruled out), technology brings it into reality.

Related Posts