Monday, November 11, 2024

React Profiler: A Step by step guide to measuring app performance

 

As react applications are becoming more and more complex, measuring application performance becomes a necessary task for developers.

React provides a built in performance monitoring tool called the react profiler

React profiler allows developers to measure individual component performance in their applications

The profiler measures the time it takes to render a component and provides critical insights with regards to the components rendering behaviour including how often the component renders and the cost of rendering the component

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Chat API and SDK.

profiler lets you measure rendering performance of a React Tree programmatically.

<Profiler id="App" onRender={onRender}>
  <App />
</Profiler>

Rendering performance Measurement

To measure rendering performance of a react component just wrap it inside ht component

like so

<App>
  <Profiler id="navbar" onRender={onRender}>
    <Navbar />
  </Profiler>
  <PageContent />
</App>

It takes two props

  1. onRender function: React calls this function anytime the component within the tree commits an update
  2. id: A string id a

Note: Profiler component lets you gather measurements programtically. If you are looking for a UI based profiler the Profiler tab in react development tools will work for you

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Chat API and SDK.

onRender Callback

the onRender callback receives several parameters that provide detailed information about the components rendering behaviour and resource utilization

function onRender(id, phase, actualDuration, baseDuration, startTime, commitTime) {
  // information regarding rendered components...
}
  1. id: It is a unique identifier for the profiler. id is a string prop that lets you identify the profiler tree that has been just committed or which part of the tree was committed if you are using multiple profilers
  2. phase: mount, update or nested update. Lets you know whether the tree has been mounted for the first time or re rendered due to a change in props state or hooks
  3. actualDuration: time spent in milliseconds rendering the and its children for the current update. Ideally this should decrease after the first render and not many components need to re render if specific props change
  4. baseDuration: the amount of time in milliseconds that would be required to re render the entire profiler subtree. It is calculated by adding recent render durations of each component in the tree. It is a worst case cost of rendering
  5. startTime: A timestamp indicating when react started rendering the components current update
  6. endTime: A timestamp indicating when react stopped rendering the components recent update.

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Chat API SDK.

Measuring different parts of an Application

the <Profiler> component can be used in multiple places to measure different parts of an application

<App>
  <Profiler id="navbar" onRender={onRender}>
    <Navbar />
  </Profiler>
  <Profiler id="Content" onRender={onRender}>
    <Content />
  </Profiler>
</App>

You can also nest <Profiler> components

<App>
  <Profiler id="Navbar" onRender={onRender}>
    <Navbar />
  </Profiler>
  <Profiler id="Content" onRender={onRender}>
    <Content>
      <Profiler id="Editor" onRender={onRender}>
        <Editor />
      </Profiler>
      <Preview />
    </Content>
  </Profiler>
</App>

Although profiler is a lightweight component. It does add some CPU overhead and should be used when necessary.

Examples

1. Data table component

Consider a data table component that displays large number of records. Whenever new data is fetched the data table is updated, potentially causing performance issues

let us try to find the bottlenecks using the profiler component and fix the issues

import { Profiler } from 'react';
import TableInfo from './TableInfo';

function App() {
  return (
    <Profiler id="TableInfo" onRender={onRenderCallback}>
      <DataTable />
    </Profiler>
  );
}

function onRenderCallback(
  id,
  phase,
  actualDuration,
  baseDuration,
  startTime,
  endTime,
) {
  console.log(`Profiler [${id}] - ${phase} - ${actualDuration} ms`);
}
  1. Wrap the component in the profiler component and provide and id and an onRender function on callback
  2. The onRenderfunction gives you the following parameters when the table renders on screen
  3. id,
  4. phase,
  5. actualDuration,
  6. baseDuration,
  7. startTime,
  8. endTime,
  9. log the total time and phase to the console and note the readings then

Add the profiler to the child components as well like

import { Profiler } from 'react';
import ChildComponent from './ChildComponent';

function ParentComponent() {
  return (
    <div>
      <Profiler id="ChildComponent" onRender={onRenderCallback}>
        <ChildComponent />
      </Profiler>
    </div>
  );
}

Analyze the performance of each child component using actualDuration and phase and startTime and endTime.

2. Measuring the performance of a Form Component with validation

In this example we have a complex form with multiple input fields and form validation. This form can have performance issue when validation is triggered on each input change

import { Profiler } from 'react';
import ExpensiveForm from './ExpensiveForm';

function App() {
  return (
    <Profiler id="ExpensiveForm" onRender={onRenderCallback}>
      <ExpensiveForm />
    </Profiler>
  );
}

function onRenderCallback(
  id,
  phase,
  actualDuration,
  baseDuration,
  startTime,
  commitTime,
  interactions
) {
  console.log(`Profiler [${id}] - ${phase} - ${actualDuration} ms`);
}

3. Infinite scroll: Identify performance issues using profiler

we have a list component that displays data using infinite scroll functionality

There might be performance issues with excessive re rendering of data. We will be using react profiler to debug these issues

import { Profiler } from 'react';
import InfiniteScrollList from './InfiniteScrollList';

function App() {
  return (
    <Profiler id="InfiniteScrollList" onRender={onRenderCallback}>
      <InfiniteScrollList />
    </Profiler>
  );
}

function onRenderCallback(
  id,
  phase,
  actualDuration,
  baseDuration,
  startTime,
  commitTime,
  interactions
) {
  console.log(`Profiler [${id}] - ${phase} - ${actualDuration} ms`);
}

Let us analyze the performance data using the react profiler. analyze and debug unusually long re renders of the list in the InfiniteScrollList component

**debounce **the scroll event: Delay the rate at which the scroll handler finds new items to show

memorization: React.memo() can be used to prevent un necessary re renders

4. Expensive Computation: Analysing performance

Let us take a component that does expensive computation. Maybe it has a large data set or some other reason for being computationally intensive

We want ot analyse the component and identify performance bottlenecks

  1. We need to wrap the expensive computation component inside a Profiler component with an id and a onRenderCallback function
import { Profiler } from 'react';
import ExpensiveComputation from './ExpensiveComputation';

function App() {
  return (
    <Profiler id="ExpensiveComputation" onRender={onRenderCallback}>
      <ExpensiveComputation />
    </Profiler>
  );
}

implement the onRenderCallback function to retun the performance data collected by the profiler like so

function onRenderCallback(
  id,
  phase,
  actualDuration,
  baseDuration,
  startTime,
  endTime
) {
  console.log(`Profiler [${id}] - ${phase} - ${actualDuration} ms`);
}

Just optimize the application and run the profiler again.

Conditional rendering: Analyzing performance

We have a component with several children and they render conditionally based on the components state.

We need to analyze the rendering performance of these child components to ensure that they render only when necessary

import { Profiler } from 'react';
import ComponentConditionalRendering from './ComponentConditionalRendering';
import ChildRE from './ChildRE';
import ChildCD from './ChildCD';

function App() {
  return (
    <Profiler id="ComponentConditionalRendering" onRender={onRenderCallback}>
      <ComponentConditionalRendering>
        <Profiler id="ChildRE" onRender={onRenderCallback}>
          <ChildRE />
        </Profiler>
        <Profiler id="ChildCD" onRender={onRenderCallback}>
          <ChildCD />
        </ComponentConditionalRendering>
    </Profiler>
  );
}
function onRenderCallback(
  id,
  phase,
  actualDuration,
  baseDuration,
  startTime,
  endTime
) {
  console.log(`Profiler [${id}] - ${phase} - ${actualDuration} ms`);
}

Lets wrap the component in the component and provide the profiler with an id and an onRender function

the onRender function will return the following parameters : id,
phase,
actualDuration,
baseDuration,
startTime,
endTime

analyze the performance and make improvements if needed and then re run the profiler to check if everything is working as it is supposed to

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Chat API SDK.

React Profiler vs React DevTools Profiler

  • React Profiler is a component which can measure specific components of a react application
  • Devtools profiler is a visual profiler and part of the react devtools chrome / browser extention
  • You need to wrap the react Profiler around a component to gether data with regards to the component
  • React Dev tools profiler is a complete visual profiler into the performance of an react application

Benefits of using react profiler

  • Performance Bottlenecks identification: You can measure rendering performance of individual components with the profiler component. This enables you to find out what is creating a performance bottleneck and fix the issue
  • **Monitoring component rendering behaviour: **You can find out what unnecessary renders are happening and optimize components by reducing their rendering costs by monitor how often a component is rendering and what is the cost of each render
  • Performance data visualization when used with devtools react profiler helps visualize the performance of react applications making it easy to understand, identify and resolve performance issues

Disadvantages of react profiler

  • Only works in development mode: The react profiler only works in the development mode and thus you can measure the performance in production. To measure performance in production need to enable a special production build with profiling enabled
  • Performance overhead during profiling: recording performance requires cpu and resources although profiler tries to be easy on the resources but does consume resources during profiling

Disadvantages of react profiler

  1. **Only works in development mode: **The react profiler only works in the development mode and thus you can measure the performance in production. To measure performance in production need to enable a special production build with profiling enabled
  2. **Performance overhead during profiling: **recording performance requires cpu and resources although profiler tries to be easy on the resources but does consume resources during profiling

Conclusion

In this article we explained how the react profiler works. React profiler is an excellent tool to measure performance of a react application

You can optimize component specific performance also react profiler can be nested within other components

  • Purpose: React profiler is a performance measurement tool helping you analyse react component, identify bottlenecks and reduce unnessasory re renders
  • Built in profiler: React dev-tools has a built in profiler which provides a visual interface for analyzing rendering performance of components. You can use react profiler in congulation with the dev tools profiler
  • : The profiler component can be used to measure the performance of a specific component. Profiler components can be nested as well. Profiler takes two props an id and a onRenderCallback function
  • onRenderCallback: onRenderCallback is a function that you pass to the component. It returns various performance metrics that can be used to measure performance

React Profiler: A Step by step guide to measuring app performance

  As react applications are becoming more and more complex, measuring application performance becomes a necessary task for developers. React...