Showing posts with label Performance improvement. Show all posts
Showing posts with label Performance improvement. 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.

September 20, 2019

Performance issues with SPFx web parts [Solution: Fix it with implementing renderCompleted & isRenderAsync methods]

We mostly encounter performance related issues, like - Page takes very long time to load all features while working with highly customized SharePoint site. To identify performance issue of Custom SPFx web parts, Microsoft suggests to implement RenderCompleted method.

I searched over the internet but did not find any good documentation on how to implement it. After spending time on analysis & research, finally I was able to implement it successfully.

Here, I am providing you with detailed steps to implement renderCompleted & isRenderAsync methods to identify performance of custom webparts.

Solution - To implement such methods, open custom web part source code - solution in Visual studio.
  • Open Interface file and add below property to it.
    asynccompfunc:() => void;
  • Now, go to the ".ts" file of your custom webpart and add below highlighted code in "Render" Method.
          public render(): void
            {
               const element: React.ReactElement<ISubmitNewsProps> = React.createElement(                                 SubmitNews,
                 {
                    // other properties...,
                    asynccompfunc:this.renderCompleted
                  });

                ReactDom.render(element, this.domElement);   
            }
  • Also, add below code after "Render" Method.
           protected renderCompleted(): void { 
                super.renderCompleted();   
           }

           protected get isRenderAsync(): boolean { 
               return true;   
           }


  • Now open ".tsx" file and add below code in "componentDidMount" method.
         //Init Function of component mount 
           public async componentDidMount() {
           
            //your code
           
           this.props.asynccompfunc();
         }


After applying all changes in your web part, deploy package and open the page where you have added the webpart.

Click "Ctr + F12". to see the performance of your web part.


Note: This method requires "BaseClientSideWebPart" class to be extended. Application Customizer does not extend this class. So we cannot implement this method in Application Customizer.

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