React Performance Optimization Guide

react
performance
optimization

Use Production Build

Always use the production build of React in production environments:

npm run build

Code-Splitting with React.lazy and Suspense

import React, { Suspense, lazy } from 'react';
 
const OtherComponent = lazy(() => import('./OtherComponent'));
 
function MyComponent() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <OtherComponent />
    </Suspense>
  );
}

Memoization

React.memo for Functional Components

const MyComponent = React.memo(function MyComponent(props) {
  /* render using props */
});

useMemo for Expensive Calculations

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

useCallback for Callbacks

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

Virtualization for Long Lists

Use react-window or react-virtualized for rendering large lists:

import { FixedSizeList as List } from 'react-window';
 
function Row({ index, style }) {
  return <div style={style}>Row {index}</div>;
}
 
function Example({ items }) {
  return (
    <List
      height={150}
      itemCount={items.length}
      itemSize={35}
      width={300}
    >
      {Row}
    </List>
  );
}

Avoid Inline Function Definitions in Renders

Instead of:

<button onClick={() => handleClick(id)}>Click me</button>

Do:

const handleClick = useCallback((id) => {
  // handle click
}, []);
 
// In render:
<button onClick={() => handleClick(id)}>Click me</button>

Use Fragment to Avoid Additional HTML Element Wrappers

import React, { Fragment } from 'react';
 
function ListItem({ item }) {
  return (
    <Fragment>
      <dt>{item.term}</dt>
      <dd>{item.description}</dd>
    </Fragment>
  );
}

Avoid Using Index as Key for Map

Instead of:

{items.map((item, index) => (
  <Component key={index} {...item} />
))}

Do:

{items.map((item) => (
  <Component key={item.id} {...item} />
))}

Debouncing and Throttling

Use lodash's debounce or throttle for handling frequent event callbacks:

import { debounce } from 'lodash';
 
const debouncedHandleChange = debounce(handleChange, 300);
 
function handleChange(e) {
  // Handle the event
}
 
// In render:
<input onChange={debouncedHandleChange} />

Use Web Workers for CPU Intensive Tasks

// worker.js
self.addEventListener('message', (e) => {
  const result = expensiveOperation(e.data);
  self.postMessage(result);
});
 
// In your React component
const worker = new Worker('worker.js');
worker.postMessage(data);
worker.onmessage = (e) => {
  setResult(e.data);
};

Remember, always measure performance before and after optimization to ensure your changes are having the desired effect. Use React DevTools Profiler and Chrome DevTools Performance tab for detailed analysis.