React Performance Optimization: Techniques You Should Be Using in 2023

Published: 10 March 2023

Introduction

Performance optimization is crucial in modern React applications, especially with the introduction of React Server Components (RSC), Concurrent Rendering, and Automatic Batching in React 18 and beyond. While React is designed to be fast, inefficient rendering and poor state management can lead to laggy UIs, slow load times, and unnecessary re-renders.

This guide will cover the best techniques to optimize performance in React applications, including:

  • Reducing unnecessary renders with React.memo, useMemo, and useCallback.
  • Leveraging React Server Components (RSC) for smaller bundle sizes.
  • Optimizing state management with Recoil, Zustand, and Jotai.
  • Using code-splitting and lazy loading to speed up initial page loads.

Let’s dive in.


1. Avoid Unnecessary Re-Renders with Memoization

Why Unnecessary Re-Renders Happen

React components re-render when their state or props change. However, sometimes a component re-renders even when its data hasn’t changed, leading to wasted processing.


Solution 1: Use React.memo for Component Memoization

React.memo prevents a component from re-rendering unless its props change.

Before Optimization (Inefficient Component Re-Rendering)

const User = ({ name }) => {
  console.log("User component re-rendered");
  return <p>{name}</p>;
};

const UserList = ({ users }) => {
  return (
    <div>
      {users.map((user) => (
        <User key={user.id} name={user.name} />
      ))}
    </div>
  );
};

Even if users doesn’t change, User re-renders every time the parent renders.

After Optimization (Using React.memo)

const User = React.memo(({ name }) => {
  console.log("User component re-rendered");
  return <p>{name}</p>;
});

✅ Now, User only re-renders when its name prop changes.


Solution 2: Optimize Functions with useCallback

Functions get re-created on every render, causing unnecessary updates.

Before Optimization (Causing Unnecessary Re-Renders)

const Parent = () => {
  const handleClick = () => console.log("Clicked");

  return <Child onClick={handleClick} />;
};

Each render creates a new handleClick function, triggering re-renders in Child.

After Optimization (Using useCallback)

const Parent = () => {
  const handleClick = useCallback(() => console.log("Clicked"), []);

  return <Child onClick={handleClick} />;
};

✅ Now, handleClick is memoized and won’t trigger re-renders unless dependencies change.


Solution 3: Optimize Expensive Computations with useMemo

Expensive calculations should be memoized to avoid recomputation on every render.

Before Optimization (Recomputing on Every Render)

const sum = numbers.reduce((acc, num) => acc + num, 0);

After Optimization (Using useMemo)

const sum = useMemo(() => numbers.reduce((acc, num) => acc + num, 0), [numbers]);

sum only recalculates when numbers changes.


2. Reduce JavaScript Bundle Size with React Server Components

Why React Server Components (RSC) Matter

React Server Components (introduced in Next.js 13/14) reduce client-side JavaScript by moving logic to the server. This means:

  • Less JavaScript to download and parse → Faster page loads.
  • Pre-rendered data fetching → No need for client-side useEffect calls.
  • Better SEO and performance → Since HTML is fully rendered on the server.

How to Use React Server Components in Next.js

// app/page.tsx (Server Component)
export default async function Page() {
  const res = await fetch("https://jsonplaceholder.typicode.com/posts");
  const posts = await res.json();

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

✅ The data is fetched on the server, reducing the client-side JS bundle.


3. Optimize State Management for Faster React Apps

Common State Management Issues

  • Too much global state → Causes unnecessary re-renders.
  • Large state trees → Slow updates and poor performance.

Best Practices for Optimizing State

Use Local State Where Possible
If a state is only used inside one component, keep it local.

Use Recoil, Zustand, or Jotai for Large Apps
Libraries like Zustand and Recoil optimize reactivity better than Redux.

import create from "zustand";

const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}));

const Counter = () => {
  const { count, increment } = useStore();
  return <button onClick={increment}>{count}</button>;
};

✅ Zustand allows fast, minimal re-renders compared to traditional Redux.


4. Improve Load Times with Code-Splitting & Lazy Loading

Why Code-Splitting Helps

Instead of loading everything at once, code-splitting ensures only necessary JavaScript is loaded when needed.

Using React.lazy for Component-Based Code-Splitting

import { lazy, Suspense } from "react";

const HeavyComponent = lazy(() => import("./HeavyComponent"));

const App = () => {
  return (
    <Suspense fallback={<p>Loading...</p>}>
      <HeavyComponent />
    </Suspense>
  );
};

✅ This prevents loading large components upfront, improving performance.


5. Optimize Images & Assets for Faster Page Loads

Use Next.js Image Component

import Image from "next/image";

<Image src="/image.jpg" width={500} height={300} alt="Optimized" />;

Use WebP Instead of PNG/JPEG → Smaller file sizes, faster loads.

Lazy Load Images → Load images only when they enter the viewport.


Final Thoughts

Optimizing React performance is crucial for fast, responsive applications. In 2023, React introduced new tools like Server Components and improved Concurrent Rendering to further boost performance.

Key Takeaways

1️⃣ Reduce re-renders with React.memo, useMemo, and useCallback.
2️⃣ Use React Server Components to cut JavaScript bundle size.
3️⃣ Optimize state management by minimizing global state.
4️⃣ Improve load times with code-splitting & lazy loading.
5️⃣ Use optimized images & assets for better performance.

By following these best practices, you’ll ensure your React applications remain fast, scalable, and efficient in 2023 and beyond.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *