Showing posts with label React Framework. Show all posts
Showing posts with label React Framework. Show all posts

June 12, 2025

Performance Optimization in React: Real-World Examples

Introduction

React is powerful, but it can suffer performance issues when components re-render unnecessarily or handle more work than needed.

This guide explores 6 common performance bottlenecks in real-world applications — along with practical techniques to address them. Each example includes before-and-after code and clear explanations of what’s happening, why it matters, and how to optimize it effectively.


1. Unnecessary Re-renders in Child Components

Consider a simple Counter component that displays a number. Even if only the input field is updated, the Counter still re-renders - a common inefficiency in many apps.

Before Optimization

function Counter({ count }) {
  console.log("Counter rendered");
  return <h2>Count: {count}</h2>;
}

function App() {
  const [count, setCount] = React.useState(0);
  const [text, setText] = React.useState("");

  return (
    <div>
      <Counter count={count} />
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <input value={text} onChange={(e) => setText(e.target.value)} />
    </div>
  );
}

After Optimization (using react-window)

const Counter = React.memo(function Counter({ count }) {
  console.log('Counter rendered');
  return <h2>Count: {count}</h2>;
});

What's happening?
Every time the App component re-renders - even when updating the text input — the Counter component also re-renders.
Why it's a problem?
React re-renders all child components by default, even if their props haven’t changed. This adds up fast in large trees.
Optimization Approach
Use React.memo to prevent unnecessary re-renders by memoizing the component unless its props actually change.

2. Rendering Huge Lists Without Virtualization

Rendering thousands of DOM nodes can completely freeze your browser. If you ever render a long list — this is critical.

Before Optimization

function App() {
  const items = Array.from({ length: 10000 }, (_, i) => `Item ${i}`);

  return (
    <div style={{ height: '400px', overflowY: 'auto' }}>
      {items.map((item) => (
        <div key={item}>{item}</div>
      ))}
    </div>
  );
}

After Optimization (using react-window)

import { FixedSizeList as List } from 'react-window';

function App() {
  const items = Array.from({ length: 10000 }, (_, i) => `Item ${i}`);

  return (
    <List
      height={400}
      itemCount={items.length}
      itemSize={35}
      width={'100%'}
    >
      {({ index, style }) => (
        <div style={style}>{items[index]}</div>
      )}
    </List>
  );
}

What's happening?
All 10,000 list items are rendered and pushed into the DOM at once.

Why it's a problem?
Rendering thousands of DOM nodes is memory-intensive and causes the browser to lag or freeze.

How to fix it?
Use virtualization (react-window) to render only visible items and reuse DOM nodes during scroll. Smooth performance, minimal overhead.


3. Function Re-created on Every Render

Every render creates a new function instance (e.g., the onClick handler in a button). This can cause unnecessary re-renders of child components, especially when they are memorized.

Before Optimization

function App() {
  const [count, setCount] = React.useState(0);
  return <Button onClick={() => setCount(count + 1)} />;
}

After Optimization

const handleClick = React.useCallback(() => {
  setCount((prev) => prev + 1);
}, []);
return <Button onClick={handleClick} />;

What's happening?
The inline arrow function gets recreated every time the component re-renders, so it has a new reference each time.

Why it's a problem?
If the Button component is memoized, it will still re-render because the onClick prop changes by reference.

How to fix it?
Wrap the function in useCallback to keep the reference stable across renders and avoid unnecessary updates downstream.

4. Tab Content Re-renders on Every Switch

Switching between tabs causes all tab content to unmount and remount, losing state and triggering unnecessary re-renders.

Before Optimization

{activeTab === 'profile' && <Profile />}
{activeTab === 'settings' && <Settings />}

After Optimization

const tabs = useMemo(() => ({
  profile: <Profile />,
  settings: <Settings />,
}), []);
return tabs[activeTab];


What's happening?
Each tab component mounts/unmounts when switching, resetting its internal state and triggering re-renders.

Why it's a problem?
Components lose their internal state, and there's a noticeable delay on tab switches due to remounting.

How to fix it?
Store components in `useMemo` and toggle visibility instead of remounting. This keeps the component’s state and makes switching faster.


5. Uncontrolled Component Switching to Controlled

Switching an input from uncontrolled to controlled (e.g., setting its value from undefined to a real value) leads to a React warning and a forced re-render.

Before Optimization

function Input({ value }) {
  return <input value={value} onChange={() => {}} />;
}

When value is initially undefined, this becomes uncontrolled, and when it gets a value, React throws a warning and forces a re-render

After Optimization

function Input({ value }) {
  return <input value={value ?? ''} onChange={() => {}} />;
}

What's happening?
If value starts as undefined, React treats the input as uncontrolled. When it gets a value later, it switches to controlled — and React throws a warning.
Why it's a problem?
Switching from an uncontrolled to a controlled input in React causes the field to reset and displays a warning.
How to fix it?
Use a fallback value (value ?? '') to keep the input controlled from the beginning, avoiding warning and preserving expected behavior.


6. Large Components Doing Too Much

Rendering too many components at once in a large bundle can delay the first paint, making your app feel slow and unresponsive.

Before Optimization

function Dashboard() {
  return (
    <>
      <HeavyChart />
      <LiveFeed />
      <WeatherWidget />
      <NotificationPanel />
    </>
  );
}

All components are rendered and mounted at once.

After Optimization (Code Splitting)

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

function Dashboard() {
  return (
    <Suspense fallback={<Loader />}>
      <HeavyChart />
      {/* Other components can load similarly */}
    </Suspense>
  );
}

What's happening?
All dashboard components are loaded upfront, even if they’re not visible or immediately needed.

Why it's a problem?
It bloats the initial JavaScript bundle, slowing down your app's first render and hurting metrics like LCP.

How to fix it?
Use React.lazy with Suspense to load components only when you need them. This helps the app load faster and feel more responsive.


Final Thoughts

Performance issues in React often creep in silently - small inefficiencies that add up as your app grows. These optimization patterns are widely applicable and can help improve performance and user experience across React applications of all sizes.

October 20, 2022

Create Dynamic Timeline Component in React JS/TS.


SCENARIO

While working on one of the requirements for an Automobile sector project for a client based out of Dallas, Texas, There was a requirement to display dynamic timeline component with Expand/Collapse feature using React JS/TS.


CHALLENGE


There is no OOTB module OR component which we can utilize in React to meet this requirement. The only option is to develop custom component using JS/TS. 

APPROACH

We are going to create a custom and complete dynamic timeline component with additional feature like expand and collapse in React JS/TS.

Please follow the below details steps to meet requirement.

Step 1: 

Create React JS or React TS application. We can use following commands respectively for React JS and React TS.

    npx create-react-app timeline --template typescript

    npx create-react-app timeline

Step 2:

Once you execute the above command in your terminal you will get the following structure of your React Project.

Step 3 :

After Creating the project we need to add some plugin which you can install by executing the following commands.

    npm i @fortawesome/react-fontawesome

    npm i @fortawesome/free-solid-svg-icons

Step 4:

Now, Clear the project structure and we have to add new two files named as : Timeline.tsx and App.tsx.


Step 5:

Add the following Code to the Timeline.tsx file

In the above code we have defined function interface and the state as follows:

Interface Props : In React JS we get the Props directly from the parent component but in React TS we have to pass interface and from interface we get the props functions and variables. 

here we have one object for the timeline details and one function for the callback to set the state of Parent component.

updateStatus Function : This function will take the updated status as the argument and the object of timeline. So, this function will take both as a argument and update the status of current state and call the callback function from Props to and pass updated Timeline information object.

In render method we have taken a const variable timelineData which takes values from Props and then we have a return function which returns the timeline View based on different condition. Also, We have one flag named as "isOpen" which basically show the view between expand or collapse.

Step 6 : 

Once we are done with the timeline component, we will move to main App.tsx component. 

Add the following code to the App.tsx file. We can directly move this code into Index.tsx , but we want to create a dynamic component so we are adding a new component names as App.tsx 

In this file we have defined one static state object named as "timelineDetails". It contains the information of the timeline which we want to show on the component view as well as set flag to show status and expand collapse position. 

We also have one function names as "updateRecord", It accepts data as an argument which is an object of the timelineDetails. this function is going to be called from the Timeline.tsx file means the child component. This function finds the matching object from the timelineDetails and store in "tempTimeline" and then will replace the states object with the updated one.

Step 7 : 

Now add the following css to the App.css file for the designing and the expand/collapse view.

Step 8 :

At last, now execute the code and you will get below output with look & feel.


Expand View:


Collapse View : 


Conclusion : 

This component will create the dynamic view along with look & feel as per requirement. We can use this Timeline.tsx in any component outside of this project but we have to take care about the function and its parameter. 

We can use this timeline component as independent component with the expand and collapse functionality with complete dynamic Content.

December 2, 2020

How to clear Office UI Fabric multi-select dropdown in SPFx webpart with React Framework?

Scenario:

We implemented a webpart using SharePoint Framework (SPFx) that includes the filter functionality. As per the requirement, we have one dropdown that allows multiple options selection for filter functionality. Now when user clicks on the "Clear Filter" button, it should clear the selection of options from the dropdown.

Below is our dropdown control with multiple items selection:
 <Dropdown  
  multiSelect  
  className="multiSelectDrodpown"  
  options={currentObj.state.dropdownOptions}  
  defaultSelectedKeys={this.state.selectedOptions}  
  onChanged={(val) => currentObj.filterData(val)}           
 ></Dropdown>  

Note:
  • dropdownOptions state contains all the options which will be display in multi select dropdown control.
  • selectedOptions is the state which contains the options which are currently selected.


Problem Statement:

  • When we select the values from the multi-select dropdown control, we pass those values to defaultSelectedKeys parameter of the multi-dropdown control to show the selected values. 
  • But when we clear the value of the state which we are using in defaultSelectedKeys parameter(selectedOptions state in our scenario), it does not clear the selection of multi-select dropdown.


Solution:

  • To resolve this issue, we need to use the "key" parameter of the office fabric UI dropdown control and set the unique number as the value on click event of the "Clear Filter" button.
  • Using a new value for key parameter means, it renders fresh control each time.
  • Here, we use randomIndex state to set a new key value to generate a random number. Below is an example to use key attribute:
 <Dropdown  
  multiSelect  
  className="multiSelectDrodpown"  
  options={currentObj.state.dropdownOptions}  
  defaultSelectedKeys={this.state.selectedOptions}  
  onChanged={(val) => currentObj.filterData(val)}     
  key={this.state.randomIndex}        
 ></Dropdown>  
  • Now, when user clicks the "Clear Filter" button, it will update randomIndex state and set a new random number as its value.
  • Here, we are using Math.floor and Math.random()  function to generate random numbers.
 private async clearFields() {  
      await this.setState({    
          randomIndex: Math.floor(Math.random() * 6) + 1          
       });  
 }  


Conclusion:

This is how we can clear the value of multi-select dropdownlist in SharePoint Framework (SPFx).

If you have any questions you can reach out our SharePoint Consulting team here.

March 30, 2020

Manage more than 100 API calls with Batch Request in SharePoint Framework (SPFx) using React

Requirement:
We have IDs of 1000 list items and want to fetch list items for only those particular IDs using Rest API with OR condition in the filter.

Problem Statement:
  1. If we append all IDs in the filter parameter with OR condition, it will give REST API length limitation (255 characters).
  2. If we use API with OR condition for all IDs and use this API in a batch request, batch API will return a blank array.
  3. If we create API for each ID and create an array of APIs & use this array in a batch request, it will work for maximum up to 100 APIs only. As we have 1000 list items to be retrieved, this will also not work due to the 100 APIs limit with a single batch request.

Solution:
We can create API for 100 Item IDs with OR condition in the filter API and create a bunch of 100 APIs in an array and then use this array in a batch request.

You can find batch utility code here on GitHub. Here is the code snippet for this solution:
 //Here we have imported batchutility.ts  
 import { BatchUtils } from "../../BatchUtils";  
 public componentDidMount() {  
   var listItemIds = [1, 2, 3, 4, 5, 6, ..............................., 1000];  
   var url = this.props.SPUrl + "/_api/web/lists/getbytitle('" + this.props.projectPhaseListName + "')/items?$filter=";  
   this.getDashboardBatchData(listItemIds, 0, listItemIds.length, url);  
 }  
 //Below function will create bunch of filters with max of 100 id in filter with or condition  
 public getDashboardBatchData(listItemIds, Index, totalCount, url) {  
   var loopLen = Index + 100;  
   if (Index <= totalCount) {  
     var filterString = "";  
     var tempApi = '';  
     var callNext = true;  
     if (totalCount > Index && totalCount < loopLen) {  
       loopLen = totalCount;  
       callNext = false;  
     }  
     for (var i = Index; i < loopLen; i++) {  
       if (filterString == '') {  
         filterString = "ID eq " + listItemIds[i];  
       }  
       else {  
         filterString += " or ID eq " + listItemIds[i];  
       }  
     }  
     tempApi = url + filterString;  
     dashboardBatchArray.push(tempApi);  
     if (callNext) {  
       this.getDashboardBatchData(listItemIds, loopLen, totalCount, url);  
     }  
     else {  
       //dashboardBatchArray will have all APIs with max of 100 filters for ID  
       this.processBatch(dashboardBatchArray);  
     }  
   }  
   else {  
     //dashboardBatchArray will have all APIs with max of 100 filters for ID  
     this.processBatch(dashboardBatchArray);  
   }  
 }  
 //Below funcion will create bunch of 100 APIs and will be used in batch request  
 public processBatch(dashboardBatchArray){  
   var index = 0;  
   var arrayLength = dashboardBatchArray.length;  
   var tempArray = [];  
   var chunk_size = 100;  
   //Below code will create array of 100 APIs in single bunch  
   for (index = 0; index < arrayLength; index += chunk_size) {  
     var myChunk = dashboardBatchArray.slice(index, index + chunk_size);  
     tempArray.push(myChunk);  
   }  
   //Below code will execute all apis of tempArray  
   let listItemsArray = [];  
   for (var i = 0; i < tempArray.length; i++) {  
     await BatchUtils.GetBatchAll({ rootUrl: this.props.SPUrl, FormDigestValue: '', batchUrls: tempArray[i] }).then((batchResult) => {  
       if (batchResult.length > 0) {  
         for (var i = 0; i < batchResult.length; i++) {  
           for (var j = 0; j < batchResult[i].d.results.length; j++) {  
             listItemsArray.push(batchResult[i].d.results[j]);  
           }  
         }  
       }  
     }  
   }  
   //You will see all 1000 items in listItemsArray variable  
   console.log(listItemsArray);  
 }  

If you have any questions you can reach out our SharePoint Consulting team here.