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:
- Lazy-loading code/resources (often via
import()/React.lazy()/ route code-splitting). - Conditionally rendering a component (often via
if/else, returningnull, 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:
// 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:
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:
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
showChartflips fromfalsetotrue, React mountsChartHeavyand runs its effects. - When it flips back, React unmounts it and runs cleanup.
- Local
useStateinsideChartHeavyis 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:
function Page({ showChart }: { showChart: boolean }) {
return (
<div hidden={!showChart}>
<ChartHeavy />
</div>
);
}In this version:
ChartHeavymounts once.- Effects run once (plus any re-renders).
- Switching
hiddenjust 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)
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.”
Related content
Why Your Animations Stutter - Batch Your DOM Style Changes
Changing four style properties one by one triggers four reflows. One class toggle triggers one. Here's how to stop the browser from doing unnecessary work.
Read moreStop Computing the Same Thing Twice - Cache Your Function Results
Your notification feed formats "2 hours ago" fifty times for fifty items. Most share the same timestamp. A simple cache cuts the work to a handful. Here's when to use a Map vs React's cache().
Read moreUse Set for Membership Checks - Not .includes()
You're filtering items by allowed IDs. Each check does array.includes() - O(n) per item. A Set gives you O(1). Same result, much faster.
Read more