🧪 How I'm Thinking About React Performance in 2025

🧪 How I'm Thinking About React Performance in 2025

Lately I’ve been diving deeper into performance tuning for React apps — especially now that features like Server Components, Concurrent Rendering, and edge deployment are more mature and ready for production.

I came across a solid article that breaks down how to think about React performance today, and I wanted to share the key points + some of my own thoughts.

Here’s a quick breakdown:


1. React Server Components (RSC)

They run on the server, so there’s no JS sent to the client for that part. This helps reduce bundle size and makes pages faster to load. Use it when you’re rendering data-heavy components that don’t need interaction.

// only runs on the server

export default async function ProductList() {
  const products = await fetchProductsFromDB();
  return <ProductGrid items={products} />;
}        

Just be sure not to use useState or useEffect in these components — they’re not meant for the browser.


2. Concurrent Rendering with useTransition and useDeferredValue

This helps React stay responsive by letting you delay less important updates.

  • useTransition is great when you want to update the UI without blocking user input.
  • useDeferredValue is useful when passing down heavy props like search results.

const [isPending, startTransition] = useTransition();

function handleSearch(input) {
  startTransition(() => {
    setSearchQuery(input);
  });
}        

3. Lazy Loading and Code Splitting

Break big components or routes into smaller chunks so users don’t have to download everything at once.

const HeavyComponent = dynamic(() => import('./HeavyComponent'), { ssr: false });        

In Next.js, next/dynamic is a great way to handle this.


4. Edge Rendering

Deploying components closer to the user (with Vercel Edge Functions or Cloudflare Workers) reduces latency and makes things feel faster — especially for dynamic content.

export const config = {
  runtime: 'edge',
};        

5. Memoization (When It Makes Sense)

Use React.memo, useMemo, and useCallback when the component is heavy and props don’t change much. But don’t wrap everything blindly — sometimes memoizing adds more overhead than benefit.

const ExpensiveChart = React.memo(({ data }) => {
  // chart rendering
});        

6. Tools to Measure Performance

Some tools I always come back to:

  • React Profiler (in DevTools) → helps find unnecessary re-renders
  • Chrome DevTools Performance tab
  • Lighthouse for Web Vitals


7. Old Techniques That Don’t Make Sense Now

Avoid stuff like:

  • shouldComponentUpdate (just use React.memo)
  • manual debounce in every component (use useTransition)
  • forcing re-renders with key tricks (usually a sign of a deeper issue)
  • global state overuse — prefer scoped state or fetch-as-you-go


🔍 Example Use Case

A product search page with 1000+ items:

✅ Server-render the product list

✅ Use useTransition for filters

✅ Defer search input updates

✅ Lazy load modals

✅ Deploy on the edge

Result: Load time under 1 second on 3G, 40% lower input delay


If you’re building with React 19 and Next.js 15, these tools can make a big difference — not just in performance, but in how smooth everything feels for the user.

🔗 Source

To view or add a comment, sign in

More articles by Milad Joodi

Others also viewed

Explore content categories