Top 10 Tips To Optimise Your React Application

Shubham Gupta
7 min readMay 19, 2023

--

Because changing the actual DOM is costly, React uses the concept of a virtual DOM to lessen the performance cost of re-rendering a webpage. This is advantageous since it minimises the time it takes for the UI to render. However, if a complex software is poorly maintained, this method can cause it to lag.
When the state change has no effect on the child components, a problem develops. In other words, they do not receive any props from the parent component. React, on the other hand, re-renders these child components. As a result, whether or not a prop is assigned to them, as long as the parent component re-renders, all of its child components re-render. This is the default behaviour of React.

Profiling the React app in order to identify bottlenecks
Using the Profiler in the React Developer Tools, we can measure the performance of the apps. We can collect performance data there anytime our application renders. The Profiler logs how long it takes a component to render, why it is rendering, and other information. We can then investigate the impacted component and perform the appropriate optimisation. Install the React DevTools for your preferred browser to use the Profiler. If you don’t already have it, go to their extension page and install it (Chrome or Firefox). When working on a React project.

Here Are Some Method that can be used to optimise the performance

Keeping State Local where needed

A state update in a parent component re-renders the parent and its child components, as we’ve seen. So, to ensure that re-rendering a component only occurs when necessary, we can remove the code that cares about the component state and make it local to that code.

import { useState } from "react";

export default function App() {
const [input, setInput] = useState("");

return (
<div>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
/>
<h3>Input text: {input}</h3>
<ChildComponent />
</div>
);
}

function ChildComponent() {
console.log("child component is rendering");
return <div>This is child component.</div>;
};

Here, we can move state where needed ,

import { useState } from "react";

export default function App() {
return (
<div>
<FormInput />
<ChildComponent />
</div>
);
}

function FormInput() {
const [input, setInput] = useState("");

return (
<div>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
/>
<h3>Input text: {input}</h3>
</div>
);
}

function ChildComponent() {
console.log("child component is rendering");
return <div>This is child component.</div>;
}

2. Avoid using Index as Key for map

Let’s assume You are rendering a list using index such that,

{
list.map((item, index) => {
<ListItem
{..item}
key={index} />
})
}

Because the key is used to identify DOM elements, utilising it as an index may cause your app to display inaccurate data. If you push or remove an item from the list with the same key as previously, React assumes the DOM element represents the same component.

If your data does not have any unique properties, consider utilising the “shortid” module, which generates a unique key.

import shortid from  "shortid";

{
list.map((item, index) => {
<ListItem
{..item}
key={shortid.generate()} />
})
}

However, if the data has a unique property, such as an ID, then it’s better to use that property.

In certain cases, it’s completely okay to use the index as the key, but only if below condition holds:

  • The list and items are static
  • The items in the list don’t have IDs and the list is never going to be reordered or filtered
  • List is immutable

Some Key Points

  • key is not really about performance, it’s more about identity (which in turn leads to better performance). randomly assigned and changing values are not identity
  • We can’t realistically provide keys without knowing how your data is modeled. I would suggest maybe using some sort of hashing function if you don’t have ids

3. Use a Function in ‘SetState’

We recommend using a function and not an object in the setState function. This suggestion is because state changes aren’t implied immediately, as conveyed by React docs. Thus, instead of this:

setState({isActive: !state.isActive});

// Use this instead
setState((prevState, props) => {
return {isActive: !prevState.isActive});
}

4. Function/Stateless Components and React.PureComponent

Function components and PureComponent in React give two distinct techniques of optimising React programmes at the component level.

Function components, which minify better than classes, prevent the creation of class instances while reducing overall bundle size.

To optimise UI updates, however, we can consider converting function components to a PureComponent class (or a class with a specific shouldComponentUpdate method). However, if the component does not employ state or other life cycle methods, the initial render time is slightly longer when compared to function components with potentially faster updates.

When is it OK to utilise React.PureComponent?

PureComponent performs a superficial comparison on state change. This means that it compares values for primitive data types and references for objects. As a result, when utilising React, we must ensure that two conditions are met.PureComponent:

Component State/Props is a non-changing object.

A multi-level nested object in a state/properties should be avoided.

Pro Tip: All React child components should be a Pure or functional component as well.

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

Lazy loading is a great technique for optimizing and speeding up the render time of your app. The idea of lazy loading is to load a component only when it is needed. React comes bundled with the React.lazy API so that you can render a dynamic import as a regular component. Here instead of loading your regular component like this:

import LazyComponent from './LazyComponent';

You can cut down the risk of performance by using the lazy method to render a component.

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

React.lazy expects a function to call a dynamic import(). This will then return a Promise pointing to a module with a default export that includes a React component.

The lazy component should be presented within a Suspense component, allowing you to add fallback material as a loading state while the lazy component loads.

import React, { Suspense } from 'react';

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

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

6. Lazy loading Images in React

When your React application has a large number of photos, the performance of your React app is likely to suffer. This occurs because the DOM renders all pictures before displaying the user interface. As a result, we recommend using Lazy loading pictures, which will wait until the image’s turn arrives on the user screen and only render that image.

Lazy loading pictures, like windowing, prevents the creation of unnecessary DOM nodes. React-lazyload and react-lazy-load-image-component are two common modules for lazy loading to improve React speed.

Here’s an example of lazy loading with react-lazy-load-image-component :

import { LazyLoadImage } from "react-lazy-load-image-component";
import "react-lazy-load-image-component/src/effects/blur.css";

export default function App() {
return (
<div className="App">
<LazyLoadImage
src={"https://placedog.net/500/300"}
width={600}
height={400}
alt="Image Alt"
effect="blur"
/>
</div>
);
}

7. Use React.Fragment to Avoid Adding Extra Nodes to the DOM

It lets you group a list of children without adding an extra node.

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

// there is also an alternate to using React.Fragments
function ListItem() {
return (
<>
<h1>Hello React!</h1>
<div>Hello React Again!</div>
</>
);
}

8. Avoid Spreading props on DOM elements

You should avoid spreading properties into a DOM element as it adds unknown HTML attribute, which is unnecessary and a bad practice.

const CommentsText = props => {
return (
<div {...props}>
{props.text}
</div>
);
};
// instead use this by specifying specific attributes
const CommentsText = props => {
return (
<div specificAttr={props.specificAttr}>
{props.text}
</div>
);
};

9. Use Reselect in Redux to Avoid Frequent Re-render

While React and Redux complement each other nicely, Redux frequently causes speed concerns owing to unneeded re-renders when a state changes. To prevent unnecessary renderings, we can utilise reselect, a Redux selector library.

Reselect has a createSelector method that can be used to create memoized selectors. A memoized selector caches its value and will only re-render or recalculate if it changes. To understand more about selectors and how they function, consult the Redux manual.

10. Use React.Memo (Memoization) & useCallback and useMemo

Most widely used for performance optimisation ,Raect.memo is a Hoc used to wrap a purely functional component to prevent re-rendering if the props received in that component never change.

Here is a memoized component which only re-renders when the item is changes.

const ListItem = React.memo(({ item, handleStatusChange }) => {
return (
<div
style={{
padding: "10px",
margin: "10px",
border: "1px solid black",
background: item?.isActive ? "green" : "red",
}}
>
{console.log("here--rendered list item", item.name)}
<div>{item?.name}</div>
<div onClick={() => handleStatusChange(item)}>
Status:{item?.isActive ? "Active" : "InActive"}
</div>
</div>
);
});

Refer here to read in detail about useCallback ans useMemo

Conclusion

The approaches described above are all excellent methods for optimising performance for your application. If you only remember one thing from this article, make it that you should always make an effort to build a performant app that will significantly improve the speed of your application and your user’s experience by first building out the project and then optimising performance where necessary; doing so will put you one step closer to making your users happy. Thank you for reading, and I hope you found this essay informative.

If you’d like to be in the know, subscribe, clap, like and share. Cheers!

--

--