Skip to main content
Arthur Ha

Performance

Lazy-Load vs Conditional Mount/Unmount - What Actually Changes

March 19, 2026

When people say “lazy-load,” they’re usually talking about deferring work until it’s needed. In React, that work can mean two different things:

  1. Lazy-loading code/resources (often via import() / React.lazy() / route code-splitting).
  2. Conditionally rendering a component (often via if/else, returning null, or choosing a different JSX branch).

They sound similar, but they change different parts of the app.

The core difference (one sentence each)

Lazy-load changes when the module/data is loaded into the app.

Conditional mount/unmount changes whether a component instance is currently mounted, which controls effects and local state.

What lazy-loading actually does

Consider a component that’s heavy because it brings a large chart library:

TSX
// ChartHeavy.tsx (big dependency)
export default function ChartHeavy() {
  // Imagine a large library + expensive initialization
  return <div>Heavy chart</div>;
}

If you lazy-load it, you typically avoid downloading that code chunk until the user needs the chart:

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

const LazyChartHeavy = lazy(() => import("./ChartHeavy"));

function Page({ showChart }: { showChart: boolean }) {
  return (
    <Suspense fallback={<div>Loading chart...</div>}>
      {showChart ? <LazyChartHeavy /> : null}
    </Suspense>
  );
}

Key point: even before the component is mounted, the app decides when the code for it should be fetched.

What if/else conditional rendering actually does

Now imagine you’re not lazy-loading the module-your component is already part of the bundle:

TSX
import ChartHeavy from "./ChartHeavy";

function Page({ showChart }: { showChart: boolean }) {
  if (!showChart) return null; // not rendered
  return <ChartHeavy />;
}

Here, the if/else only controls whether React mounts the component instance. That means:

  • When showChart flips from false to true, React mounts ChartHeavy and runs its effects.
  • When it flips back, React unmounts it and runs cleanup.
  • Local useState inside ChartHeavy is lost when it unmounts.

Lazy-loading does not automatically preserve state

People often expect “lazy-load” to behave like “keep my component’s state.” But lazy-loading controls imports, not mounting lifecycle.

If you lazy-load a component and your render logic unmounts it (e.g. returning null), its local state will still reset when it mounts again.

Unmounting vs “hiding”: state/effects are different

There’s also a third behavior that’s easy to mix up with if/else: hiding while staying mounted.

If you keep the component mounted but hide it with CSS (or the hidden attribute), effects still run because the component is still mounted:

TSX
function Page({ showChart }: { showChart: boolean }) {
  return (
    <div hidden={!showChart}>
      <ChartHeavy />
    </div>
  );
}

In this version:

  • ChartHeavy mounts once.
  • Effects run once (plus any re-renders).
  • Switching hidden just changes visibility; it does not destroy the component instance.

The practical trade-offs

Lazy-load helps you when the expensive part is:

  • large dependencies (bundle size)
  • initial initialization cost (module evaluation)
  • network fetches for data/code chunks

Conditional mount/unmount helps you when the expensive part is:

  • work that should only run for visible/active UI
  • effects that you want to stop when the UI is not needed
  • local component state that you’re okay resetting

Combine them (common best practice)

Often, the best approach is:

  • lazy-load the heavy component (reduce initial download)
  • conditionally render it (mount only when needed)
TSX
import { lazy, Suspense } from "react";

const LazyChartHeavy = lazy(() => import("./ChartHeavy"));

function Page({ showChart }: { showChart: boolean }) {
  return (
    <Suspense fallback={null}>{showChart ? <LazyChartHeavy /> : null}</Suspense>
  );
}

Rule of thumb

Use lazy-loading to reduce what the user downloads. Use if/else (or returning null) to control whether the component instance exists.

If you want both better download performance and correct lifecycle behavior, combine lazy-loading with conditional rendering.

Summary

Lazy-load and conditional mount/unmount often get grouped together, but they control different mechanisms:

  • Lazy-loading decides when code/data is loaded.
  • Conditional rendering decides whether React mounts or unmounts the component instance.

Understanding that distinction prevents bugs like “my component’s state resets” or “I hid it but effects still ran.”