DEV Community

Cover image for How to Make Your React App 10x Faster with Memoization and Code Splitting
Raji moshood
Raji moshood

Posted on

How to Make Your React App 10x Faster with Memoization and Code Splitting

Introduction

Performance optimization is crucial for building fast, efficient, and scalable React applications. Without proper optimizations, React apps can suffer from unnecessary re-renders, large bundle sizes, and sluggish performance.

This guide explores React.memo, useMemo, useCallback, lazy loading, and code splitting to help you make your React app significantly faster.

  1. Optimize Component Re-Renders with Memoization

React’s reactivity model causes components to re-render when their props or state change. Unnecessary re-renders can slow down your app, especially in large applications.

React.memo: Prevent Re-Rendering of Functional Components

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

✅ Best for pure functional components that don’t rely on state.
✅ Avoids unnecessary re-renders, improving UI responsiveness.

import React from "react";

const Button = React.memo(({ onClick, label }) => {
  console.log("Button rendered!");
  return <button onClick={onClick}>{label}</button>;
});

export default Button;
Enter fullscreen mode Exit fullscreen mode

Without React.memo, every parent re-render triggers the child’s re-render.

useMemo: Optimize Expensive Calculations

useMemo caches expensive computations so they aren’t recalculated on every render.

✅ Best for complex calculations or expensive data processing.
✅ Reduces CPU load and enhances performance.

import { useMemo } from "react";

const ExpensiveComponent = ({ items }) => {
  const sortedItems = useMemo(() => {
    console.log("Sorting items...");
    return items.sort((a, b) => a - b);
  }, [items]);

  return <div>{sortedItems.join(", ")}</div>;
};
Enter fullscreen mode Exit fullscreen mode

Without useMemo, sorting runs on every render, wasting CPU resources.

useCallback: Optimize Function References

useCallback memoizes function references to prevent unnecessary re-renders in child components.

✅ Best for passing functions as props to avoid re-renders.
✅ Works well with React.memo for performance gains.

import { useState, useCallback } from "react";

const Parent = () => {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    console.log("Button clicked!");
  }, []);

  return (
    <>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <Child onClick={handleClick} />
    </>
  );
};

const Child = React.memo(({ onClick }) => {
  console.log("Child rendered!");
  return <button onClick={onClick}>Click me</button>;
});
Enter fullscreen mode Exit fullscreen mode

export default Parent;

Without useCallback, the child re-renders unnecessarily every time the parent updates.

  1. Reduce Bundle Size with Code Splitting & Lazy Loading

By default, React applications load all components at once, leading to large bundle sizes and slow page loads. Code splitting helps load components only when needed.

React.lazy & Suspense: Load Components on Demand

✅ Best for reducing initial bundle size and improving load speed.
✅ Works well for routes, modals, and large UI components.

import React, { lazy, Suspense } from "react";

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

const App = () => (
  <Suspense fallback={<div>Loading...</div>}>
    <HeavyComponent />
  </Suspense>
);
Enter fullscreen mode Exit fullscreen mode

Without lazy loading, large components slow down the initial load time.

Dynamic Imports with Webpack Code Splitting

✅ Split code at the route level to load pages only when needed.

import dynamic from "next/dynamic";

const DynamicComponent = dynamic(() => import("../components/HeavyComponent"), {
  ssr: false,
});
Enter fullscreen mode Exit fullscreen mode

✅ Use Webpack’s import() to load dependencies dynamically.

const loadLibrary = async () => {
  const { libraryFunction } = await import("./library");
  libraryFunction();
};
Enter fullscreen mode Exit fullscreen mode

Without dynamic imports, all components and libraries are bundled upfront, increasing load time.

  1. Optimize Lists with React Virtualization

When rendering large lists, React can slow down due to DOM overload. Virtualization ensures only visible items are rendered.

✅ Use react-window or react-virtualized to optimize large lists.

import { FixedSizeList } from "react-window";

const Row = ({ index, style }) => <div style={style}>Row {index}</div>;

const List = () => (
  <FixedSizeList height={400} width={300} itemSize={35} itemCount={1000}>
    {Row}
  </FixedSizeList>
);
Enter fullscreen mode Exit fullscreen mode

Without virtualization, large lists can cause major performance issues.

  1. Avoid Unnecessary State Updates

Minimize the number of state updates to prevent excessive re-renders.

✅ Use local state where possible to avoid unnecessary re-renders.
✅ Batch state updates using useReducer or React.useState.
✅ Use context sparingly—overuse can cause unwanted re-renders.

import { useReducer } from "react";

const reducer = (state, action) => {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    default:
      return state;
  }
};

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <button onClick={() => dispatch({ type: "increment" })}>
      {state.count}
    </button>
  );
};
Enter fullscreen mode Exit fullscreen mode

Using useReducer prevents unnecessary re-renders compared to multiple useState updates.

Conclusion

Improving your React app’s performance requires a combination of memoization, lazy loading, code splitting, and efficient state management. By implementing React.memo, useMemo, useCallback, lazy loading, and virtualization, you can significantly reduce re-renders and optimize your app for speed.

I’m open to collaboration on projects and work. Let’s transform ideas into digital reality!

React #PerformanceOptimization #WebDevelopment #Frontend #ReactJS #CodeSplitting #Memoization

Top comments (0)