Skip to content

React Code Splitting Interview Guide

Code Splitting is a technique used to split a large JavaScript bundle into smaller chunks that can be loaded on demand.

  • Faster initial page load
  • Reduced bundle size
  • Better performance
  • Improved user experience
const Home = React.lazy(() => import('./Home'));

Without code splitting:

  • The entire application bundle is downloaded during startup.

With code splitting:

  • Only the required code is loaded initially.
  • Remaining code is downloaded only when needed.

Example:

  • Login page loads only login-related code.
  • Dashboard code loads after login.

  1. React.lazy()
  2. Suspense
  3. Route-based splitting
  4. Dynamic imports
  5. Webpack/Vite code splitting
const Dashboard = React.lazy(() => import('./Dashboard'));

React.lazy() allows React components to be loaded dynamically.

const Profile = React.lazy(() => import('./Profile'));

The component is downloaded only when it is rendered.


Since lazy-loaded components load asynchronously, React needs a fallback UI.

<Suspense fallback={<div>Loading...</div>}>
<Profile />
</Suspense>

Without Suspense, React throws an error.


  • Dashboard
  • Reports
  • Admin pages
  • Analytics pages
  • Settings page
  • Header
  • Navbar
  • Footer
  • Frequently used shared components

Lazy loading small, frequently rendered components adds network overhead without a meaningful bundle-size benefit.


Each route loads only when the user navigates to it.

const Dashboard = React.lazy(() => import('./pages/Dashboard'));
const Settings = React.lazy(() => import('./pages/Settings'));
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />

This is the most common enterprise approach.


Dynamic imports load modules at runtime.

import('./utils')
.then(module => {
module.calculate();
});

Static import:

import { calculate } from './utils';

Dynamic imports automatically create separate chunks.


Lazy Loading Code Splitting
Loads code when needed Splits bundle into chunks
Runtime behavior Build-time optimization
Uses React.lazy Uses Webpack/Vite

Interview Answer: Code splitting creates chunks, while lazy loading loads those chunks only when required.


flowchart LR
A[Application Starts] --> B[React.lazy Component Referenced]
B --> C[Separate JS Chunk Requested]
C --> D[Suspense Shows Fallback]
D --> E[Chunk Download Completes]
E --> F[Component Renders]

Internally:

  1. Bundler creates a separate JS chunk.
  2. Component is excluded from the main bundle.
  3. Browser downloads the chunk on demand.
  4. Suspense displays fallback UI.
  5. Component renders after download.

Use an Error Boundary to catch chunk-loading failures (e.g., network errors) that Suspense alone does not handle:

class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
<ErrorBoundary>
<Suspense fallback={<Loader />}>
<Dashboard />
</Suspense>
</ErrorBoundary>

React.lazy() expects a default export.

Incorrect:

export const Dashboard = () => {};

Correct:

export default Dashboard;

Alternative:

const Dashboard = React.lazy(() =>
import('./Dashboard').then(module => ({
default: module.Dashboard
}))
);

Chunking means breaking a large bundle into multiple smaller bundles.

main.js
vendor.js
dashboard.js
profile.js

Benefits:

  • Parallel downloads
  • Browser caching
  • Faster loading

Webpack creates chunks automatically for dynamic imports.

import('./Dashboard');

Output:

main.bundle.js
dashboard.chunk.js

Separate third-party libraries from application code.

vendor.js
react
react-dom
axios
app.js
business code

Benefits:

  • Better browser caching
  • Smaller deployments

Common tools:

  • Webpack Bundle Analyzer
  • Source Map Explorer
  • Lighthouse
Terminal window
npm install webpack-bundle-analyzer

  • Works only with default exports
  • Primarily intended for client-side rendering
  • Requires Suspense
  • Requires Error Boundaries for graceful error handling
  • First load may be slower due to network requests

Avoid using it for:

  • Frequently used components
  • Critical above-the-fold UI
  • Small reusable components

Bad:

const Button = React.lazy(() => import('./Button'));

Good:

const ReportsPage = React.lazy(() => import('./ReportsPage'));

Recommended strategies:

  1. Route-level splitting
  2. Vendor splitting
  3. Lazy load heavy chart libraries
  4. Lazy load admin modules
  5. Prefetch important chunks
  6. Use browser caching

Example:

const Analytics = React.lazy(() => import('./Analytics'));

Challenges:

  • Loading delays
  • Chunk load failures
  • Too many small chunks
  • SEO concerns
  • Suspense fallback flashing

Solutions:

  • Error Boundaries
  • Chunk prefetching
  • Intelligent chunk grouping
  • SSR frameworks such as Next.js

We Implemented Lazy Loading, But Users Still Experience Slow Navigation. Why?

Section titled “We Implemented Lazy Loading, But Users Still Experience Slow Navigation. Why?”

Possible reasons:

  1. Large lazy-loaded bundles
  2. Slow API calls
  3. Multiple nested lazy components
  4. Large images or videos
  5. Missing caching
  6. High network latency
  7. Excessive re-renders

Recommended solutions:

  • Analyze bundle size
  • Prefetch important routes
  • Cache API responses
  • Optimize images
  • Memoize components
  • Use React Query or SWR

Prefetch Preload
Low priority High priority
Used for future navigation Needed immediately

Prefetch:

<link rel="prefetch" href="dashboard.js">

Preload:

<link rel="preload" href="dashboard.js">

Code Splitting is a performance optimization technique where a large React bundle is divided into smaller chunks. Instead of downloading the entire application upfront, React loads only the required code using React.lazy and Suspense. This reduces the initial load time, improves performance, and provides a better user experience, especially in large-scale enterprise applications.

  • Code splitting reduces the initial JavaScript bundle size.
  • React.lazy() and Suspense provide built-in lazy loading for components.
  • Route-based code splitting is the most common enterprise pattern.
  • Dynamic imports automatically create separate bundles.
  • Error Boundaries help recover from chunk-loading failures.
  • Analyze bundles regularly to identify optimization opportunities.