ReactJS & JavaScript
Performance -
Comprehensive Guide
Table of Contents
1. ReactJS Optimizations by Version
2. Ecosystem Libraries
3. Webpack Performance Features
4. Performance Metrics
5. Class-Only Functionalities
6. [Link] vs shouldComponentUpdate
7. Pure Component vs Functional Component
8. JavaScript Expression Execution & Coercion
9. Web Workers & Service Workers
1. ReactJS Optimizations by Version
React has evolved significantly with each major version, introducing powerful performance improvements and new
paradigms.
React 16.6+: Lazy Loading and Code Splitting
Overview: React 16.6 introduced [Link], Lazy, and Suspense to help reduce unnecessary re-renders and
enable code splitting.
Key Features:
[Link]: Prevents unnecessary re-renders of functional components
Lazy: Enables dynamic code splitting
Suspense: Handles async component loading
Example 1: Lazy Loading Components
import React, { Suspense, lazy } from "react";
// Lazy load the Dashboard component
const Dashboard = lazy(() => import("./pages/Dashboard"));
const Analytics = lazy(() => import("./pages/Analytics"));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Dashboard />
</Suspense>
);
}
Example 2: Route-Based Code Splitting
import React, { Suspense, lazy } from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
const Home = lazy(() => import("./pages/Home"));
const UserProfile = lazy(() => import("./pages/UserProfile"));
const Settings = lazy(() => import("./pages/Settings"));
function App() {
return (
<Router>
<Suspense fallback={<LoadingSpinner />}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/profile/:id" element={<UserProfile />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
</Router>
);
}
Use Cases:
Large Dashboards: Load dashboard widgets only when needed, reducing initial bundle size
Multi-page Applications: Load different pages on-demand as users navigate
Feature Modules: Load premium features only when accessed by users
Heavy Libraries: Defer loading chart libraries until user navigates to analytics
Performance Impact:
Reduces initial bundle size by 40-60% in large applications
Improves First Contentful Paint (FCP) by loading only critical code
Better caching: Lazy-loaded chunks are cached separately
React 16.8: Hooks and Advanced Memoization
Overview: Hooks revolutionized React by allowing state management and side effects in functional components, with
useMemo and useCallback for performance optimization.
Key Features:
useMemo: Caches expensive computations
useCallback: Memoizes function references
useState: State management in functional components
useEffect: Side effects management
Example 1: useMemo for Expensive Calculations
import React, { useMemo, useState } from "react";
function DataFilterComponent({ items, filterCriteria }) {
const [sortOrder, setSortOrder] = useState("asc");
// Expensive filtering and sorting operation
const filteredAndSortedItems = useMemo(() => {
[Link]("Recalculating filtered items...");
const filtered = [Link]((item) => {
return (
[Link] === [Link] &&
[Link] >= [Link] &&
[Link] <= [Link]
);
});
const sorted = [Link]((a, b) => {
if (sortOrder === "asc") {
return [Link] - [Link];
} else {
return [Link] - [Link];
}
});
return sorted;
}, [items, filterCriteria, sortOrder]);
return (
<div>
<button
onClick={() => setSortOrder(sortOrder === "asc" ? "desc" : "asc")}
>
Toggle Sort
</button>
<div>
{[Link]((item) => (
<div key={[Link]}>
{[Link]} - ${[Link]}
</div>
))}
</div>
</div>
);
}
Example 2: useCallback with Child Components
import React, { useCallback, useState } from "react";
// Expensive child component
const UserItemComponent = [Link](({ user, onUserSelect }) => {
[Link](`Rendering user: ${[Link]}`);
return (
<div onClick={() => onUserSelect([Link])}>
{[Link]} - {[Link]}
</div>
);
});
function UserListComponent({ users }) {
const [selectedUser, setSelectedUser] = useState(null);
// Without useCallback, onUserSelect would be recreated on every render
// causing all UserItemComponent instances to re-render
const handleUserSelect = useCallback((userId) => {
setSelectedUser(userId);
[Link](`Selected user: ${userId}`);
}, []);
return (
<div>
<h2>Selected: {selectedUser}</h2>
{[Link]((user) => (
<UserItemComponent
key={[Link]}
user={user}
onUserSelect={handleUserSelect}
/>
))}
</div>
);
}
Example 3: Complex useMemo Dependency Management
import React, { useMemo, useState, useCallback } from "react";
function AnalyticsComponent({ analyticsData }) {
const [timeRange, setTimeRange] = useState("7days");
const [metrics, setMetrics] = useState(["revenue", "users"]);
// Complex calculation with multiple dependencies
const analyticsReport = useMemo(() => {
const startDate = calculateStartDate(timeRange);
return {
timeRange,
metrics: [Link]((metric) => ({
name: metric,
data: aggregateData(analyticsData, metric, startDate),
trend: calculateTrend(analyticsData, metric, startDate),
})),
summary: {
totalRevenue: calculateTotal(analyticsData, "revenue", startDate),
activeUsers: calculateTotal(analyticsData, "users", startDate),
},
};
}, [analyticsData, timeRange, metrics]);
return (
<div>
<ReportDisplay report={analyticsReport} />
</div>
);
}
Use Cases:
Large Dataset Filtering: Efficiently filter/sort 10,000+ items without performance degradation
Complex Calculations: Cache expensive mathematical or statistical computations
Memoized Selectors: Prevent child component re-renders in large lists
Form Validation: Cache validation results for large forms
Performance Impact:
Prevents unnecessary recalculations of expensive operations
Reduces child component re-renders significantly
Can improve performance by 20-50% in data-heavy applications
React 17: New JSX Transform and Bundle Optimization
Overview: React 17 eliminated the need for import React in every file using JSX, reducing bundle size and improving
the developer experience.
Key Changes:
JSX is automatically compiled without needing React import
Smaller bundle size (2-5% reduction)
Better tree-shaking and dead code elimination
Example 1: Before React 17
// Old way - required React import
import React from "react";
function MyComponent() {
return <div>Hello</div>;
}
Example 2: After React 17
// New way - no React import needed
function MyComponent() {
return <div>Hello</div>;
}
Benefit Illustration:
// Before React 17: Bundle includes unused React default export
// File size: ~42KB for simple component files combined
// After React 17: Only imports JSX runtime when needed
// File size: ~40KB for same components (5% reduction across large apps)
Use Cases:
Reducing overall bundle size in large applications
Faster build times with fewer imports to process
Cleaner, more readable code without unnecessary imports
Better code splitting as tree-shaking is more effective
Performance Impact:
2-5% reduction in overall bundle size
Faster build times due to fewer module resolutions
Better caching due to fewer import statements
React 18: Automatic Batching and Transitions
Overview: React 18 introduced automatic batching and the useTransition hook for better handling of concurrent
state updates and UI responsiveness.
Key Features:
Automatic Batching: Groups multiple state updates into a single render
useTransition: Marks non-urgent updates as transitions
Concurrent Rendering: Better responsiveness with non-blocking rendering
Example 1: Automatic Batching
import React, { useState } from "react";
function FormComponent() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false);
// Before React 18: This would cause 3 separate renders
// After React 18: Automatically batched into 1 render
const handleInputChange = (e) => {
setName([Link]);
setEmail([Link]("@[Link]", "@"));
setIsSubmitting(true);
};
return (
<div>
<input onChange={handleInputChange} value={name} />
<p>Status: {isSubmitting ? "Submitting..." : "Ready"}</p>
</div>
);
}
Example 2: useTransition for UI Responsiveness
import React, { useState, useTransition } from "react";
function SearchComponent({ users }) {
const [searchTerm, setSearchTerm] = useState("");
const [isPending, startTransition] = useTransition();
const filteredUsers = searchTerm
? [Link]((user) =>
[Link]().includes([Link]()),
)
: users;
const handleSearch = (e) => {
const value = [Link];
// Mark this state update as non-urgent (transition)
startTransition(() => {
setSearchTerm(value);
});
};
return (
<div>
<input
type="text"
onChange={handleSearch}
placeholder="Search users..."
disabled={isPending}
/>
{isPending ? (
<div>Searching...</div>
) : (
<ul>
{[Link]((user) => (
<li key={[Link]}>{[Link]}</li>
))}
</ul>
)}
</div>
);
}
Example 3: Complex Form with Multiple State Updates
import React, { useState, useTransition } from "react";
function ComplexFormComponent() {
const [formData, setFormData] = useState({});
const [errors, setErrors] = useState({});
const [touched, setTouched] = useState({});
const [isPending, startTransition] = useTransition();
const handleFieldChange = (e) => {
const { name, value } = [Link];
// Batch multiple state updates
startTransition(() => {
// Update form data
setFormData((prev) => ({
...prev,
[name]: value,
}));
// Validate
setErrors((prev) => ({
...prev,
[name]: validateField(name, value),
}));
// Mark as touched
setTouched((prev) => ({
...prev,
[name]: true,
}));
});
};
return (
<form>
<input name="email" onChange={handleFieldChange} />
<input name="password" onChange={handleFieldChange} />
<button disabled={isPending}>
{isPending ? "Validating..." : "Submit"}
</button>
</form>
);
}
Use Cases:
Smooth UI Updates: Maintain responsive UI during intensive computations
Complex Apps: Handle multiple state updates without visual jank
Search/Filter: Real-time search that doesn't block UI interactions
Form Validation: Validate forms while keeping input responsive
Performance Impact:
Eliminates unnecessary intermediate renders
Improves perceived responsiveness by 30-40% in complex applications
Better handling of rapid state updates
React 19: Compiler and Server Components
Overview: React 19 introduces the React Compiler for automatic optimization and Server Components for rendering on
the server side.
Key Features:
React Compiler: Automatically optimizes components without manual useMemo/useCallback
Server Components: Render components on the server to reduce client bundle
Actions: Simplified server mutations
Enhanced Error Handling: Better error messages and debugging
Example 1: Server Components (Framework-dependent, e.g., [Link])
// app/[Link] - Server Component by default
export default async function UserPage({ params }) {
// Direct database access in component
const user = await fetchUser([Link]);
const posts = await fetchUserPosts([Link]);
return (
<div>
<h1>{[Link]}</h1>
<PostList posts={posts} />
</div>
);
}
// Client component when needed
("use client");
import { useState } from "react";
export function PostInteractive({ post }) {
const [liked, setLiked] = useState(false);
return (
<div onClick={() => setLiked(!liked)}>
{[Link]} {liked ? "❤" : " "}
</div>
);
}
Example 2: React Compiler Optimization
// Before React 19: Manual memoization needed
import { useMemo, useCallback } from "react";
function ProductList({ products, onSelect }) {
const sortedProducts = useMemo(() => {
return [...products].sort((a, b) => [Link] - [Link]);
}, [products]);
const handleSelect = useCallback(
(id) => {
onSelect(id);
},
[onSelect],
);
return (
<div>
{[Link]((product) => (
<Product key={[Link]} product={product} onSelect={handleSelect} />
))}
</div>
);
}
// After React 19: Compiler handles optimization automatically
function ProductList({ products, onSelect }) {
const sortedProducts = [...products].sort((a, b) => [Link] - [Link]);
return (
<div>
{[Link]((product) => (
<Product key={[Link]} product={product} onSelect={onSelect} />
))}
</div>
);
}
Example 3: Server Actions for Mutations
// app/[Link] - Server file
"use server";
export async function updateUserProfile(formData) {
const name = [Link]("name");
const email = [Link]("email");
// Direct database update
const user = await [Link]({ name, email });
return user;
}
// app/profile/[Link] - Client component
("use client");
import { updateUserProfile } from "@/app/actions";
import { useFormStatus } from "react-dom";
function ProfileForm({ user }) {
const { pending } = useFormStatus();
return (
<form action={updateUserProfile}>
<input name="name" defaultValue={[Link]} />
<input name="email" defaultValue={[Link]} />
<button disabled={pending}>{pending ? "Saving..." : "Save"}</button>
</form>
);
}
Use Cases:
Reducing client-side bundle size by 20-40%
Better SEO through server-side rendering
Simplified data fetching without prop drilling
More secure mutations without exposing APIs
Performance Impact:
30-50% reduction in JavaScript sent to client
Automatic optimization by compiler
Reduced hydration time for SSR applications
Section 1 Summary Table: ReactJS Optimizations by
Version
React
Key Features Primary Benefit Best Use Case
Version
[Link], Lazy,
React 16.6+ Code splitting Large dashboards
Suspense
Expensive computations Filtering large
React 16.8 useMemo, useCallback
caching datasets
All modern
React 17 New JSX Transform Reduced bundle size
applications
Automatic Batching, Complex state
React 18 UI responsiveness
Transitions updates
Compiler, Server Full-stack
React 19 Reduced client bundle
Components applications
2. Ecosystem Libraries
The React ecosystem provides powerful libraries to enhance performance and developer experience.
RTK Query / TanStack Query: Efficient API Caching
Overview: These libraries provide intelligent caching, synchronization, and background updating of server state.
Benefits:
Automatic caching and deduplication
Background refetching
Optimistic updates
Request deduplication
Example 1: RTK Query Setup
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
// Define the API slice
export const userApi = createApi({
reducerPath: "userApi",
baseQuery: fetchBaseQuery({
baseUrl: "[Link]
prepareHeaders: (headers, { getState }) => {
const token = getState().[Link];
if (token) {
[Link]("authorization", `Bearer ${token}`);
}
return headers;
},
}),
endpoints: (builder) => ({
getUsers: [Link]({
query: () => "/users",
// Cache for 5 minutes
keepUnusedDataFor: 300,
}),
getUserById: [Link]({
query: (id) => `/users/${id}`,
}),
updateUser: [Link]({
query: ({ id, ...patch }) => ({
url: `/users/${id}`,
method: "PATCH",
body: patch,
}),
// Optimistic update
async onQueryStarted({ id, ...patch }, { dispatch, queryFulfilled }) {
const patchResult = dispatch(
[Link]("getUserById", id, (draft) => {
[Link](draft, patch);
}),
);
try {
await queryFulfilled;
} catch {
[Link]();
}
},
// Invalidate related queries after mutation
invalidatesTags: (result, error, { id }) => [
{ type: "User", id },
"UserList",
],
}),
}),
tagTypes: ["User", "UserList"],
});
export const { useGetUsersQuery, useGetUserByIdQuery, useUpdateUserMutation } =
userApi;
Example 2: Using RTK Query in Components
import React from "react";
import { useGetUsersQuery, useUpdateUserMutation } from "./userApi";
function UserListComponent() {
const { data: users, isLoading, error, refetch } = useGetUsersQuery();
const [updateUser] = useUpdateUserMutation();
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {[Link]}</div>;
const handleUpdateUser = async (userId, updates) => {
try {
await updateUser({ id: userId, ...updates }).unwrap();
} catch (err) {
[Link]("Failed to update user:", err);
}
};
return (
<div>
<button onClick={refetch}>Refresh Data</button>
{[Link]((user) => (
<UserCard key={[Link]} user={user} onUpdate={handleUpdateUser} />
))}
</div>
);
}
Example 3: TanStack Query (React Query) Approach
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
const userQueryKey = ["users"];
async function fetchUsers() {
const res = await fetch("[Link]
return [Link]();
}
async function updateUser(userData) {
const res = await fetch(`[Link] {
method: "PATCH",
body: [Link](userData),
});
return [Link]();
}
function UserListComponent() {
const queryClient = useQueryClient();
const { data: users, isLoading } = useQuery({
queryKey: userQueryKey,
queryFn: fetchUsers,
staleTime: 5 * 60 * 1000, // 5 minutes
cacheTime: 10 * 60 * 1000, // 10 minutes
});
const updateMutation = useMutation({
mutationFn: updateUser,
onSuccess: (data) => {
// Invalidate and refetch
[Link]({ queryKey: userQueryKey });
// Or update cache directly (optimistic update)
[Link](userQueryKey, (old) =>
[Link]((user) => ([Link] === [Link] ? data : user)),
);
},
});
return (
<div>
{users?.map((user) => (
<UserCard
key={[Link]}
user={user}
onUpdate={(updates) =>
[Link]({ id: [Link], ...updates })
}
/>
))}
</div>
);
}
Use Cases:
Avoiding Duplicate Requests: Multiple components requesting the same data share single request
Background Refetching: Keep data fresh without user action
Optimistic Updates: Show updates immediately while syncing with server
Complex Data Dependencies: Manage relationships between multiple data sources
Performance Impact:
Reduces API calls by 50-70% through caching
Eliminates duplicate requests automatically
Improves perceived performance with optimistic updates
Redux Persist: State Persistence
Overview: Redux Persist automatically persists and hydrates Redux store to/from local storage.
Example 1: Redux Persist Setup
import { createStore } from "redux";
import { persistStore, persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";
const persistConfig = {
key: "root",
storage,
whitelist: ["user", "preferences"], // Only persist these reducers
blacklist: ["ui"], // Don't persist UI state
throttle: 1000, // Throttle to 1000ms
};
const rootReducer = (state = {}, action) => {
switch ([Link]) {
case "SET_USER":
return { ...state, user: [Link] };
default:
return state;
}
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
export const store = createStore(persistedReducer);
export const persistor = persistStore(store);
Example 2: Using Persisted Store in App
import React from "react";
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import { store, persistor } from "./store";
import App from "./App";
function Root() {
return (
<Provider store={store}>
<PersistGate loading={<div>Loading...</div>} persistor={persistor}>
<App />
</PersistGate>
</Provider>
);
}
export default Root;
Use Cases:
User Sessions: Persist login information across page refreshes
User Preferences: Remember theme, language, layout preferences
Form Draft: Save form progress automatically
Shopping Cart: Retain cart items during browsing sessions
Performance Impact:
Eliminates need to re-fetch user data on page reload
Faster app initialization (100-500ms improvement)
Better user experience with preserved state
Reselect: Memoized Selectors
Overview: Reselect creates memoized selectors that only recalculate when their inputs change.
Example 1: Basic Reselect Usage
import { createSelector } from "reselect";
// Input selectors
const selectUsers = (state) => [Link];
const selectFilter = (state) => [Link];
// Memoized selector - only recalculates when users or filter changes
export const selectFilteredUsers = createSelector(
[selectUsers, selectFilter],
(users, filter) => {
[Link]("Calculating filtered users...");
return [Link]((user) =>
[Link]().includes([Link]()),
);
},
);
// Usage in component
import { useSelector } from "react-redux";
function UserList() {
const filteredUsers = useSelector(selectFilteredUsers);
return (
<ul>
{[Link]((user) => (
<li key={[Link]}>{[Link]}</li>
))}
</ul>
);
}
Example 2: Complex Nested Selectors
import { createSelector } from "reselect";
const selectUsers = (state) => [Link];
const selectOrders = (state) => [Link];
const selectOrderFilter = (state) => [Link];
// First level selectors
const selectUserMap = createSelector(
[selectUsers],
(users) => new Map([Link]((u) => [[Link], u])),
);
const selectFilteredOrders = createSelector(
[selectOrders, selectOrderFilter],
(orders, filter) => [Link]((order) => [Link] === filter),
);
// Complex selector combining multiple memoized selectors
const selectOrdersWithUserDetails = createSelector(
[selectFilteredOrders, selectUserMap],
(orders, userMap) => {
return [Link]((order) => ({
...order,
user: [Link]([Link]),
}));
},
);
Example 3: Selectors with Parameters
import { createSelector } from "reselect";
const selectUsers = (state) => [Link];
// Factory function for parameterized selectors
export const makeSelectUserById = () =>
createSelector([selectUsers, (state, userId) => userId], (users, userId) =>
[Link]((u) => [Link] === userId),
);
// Usage
function UserDetail({ userId }) {
const selectUserById = makeSelectUserById();
const user = useSelector((state) => selectUserById(state, userId));
return <div>{user?.name}</div>;
}
Use Cases:
Preventing Unnecessary Re-renders: Complex selector calculations that don't change
Derived Data: Calculate statistics, aggregations, or transformations
Data Normalization: Transform normalized store into denormalized UI-friendly data
Filtering and Sorting: Expensive filter/sort operations
Performance Impact:
Prevents unnecessary component re-renders (50-80% reduction in large apps)
Eliminates redundant calculations
Improves selector performance by 10-20x through memoization
React Hook Form: Uncontrolled Components
Overview: React Hook Form minimizes re-renders using uncontrolled components, improving form performance
significantly.
Example 1: Basic React Hook Form
import React from "react";
import { useForm } from "react-hook-form";
function RegistrationForm() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
const onSubmit = (data) => {
[Link](data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
{...register("email", { required: "Email is required" })}
placeholder="Email"
/>
{[Link] && <span>{[Link]}</span>}
<input
{...register("password", { minLength: 8 })}
type="password"
placeholder="Password"
/>
{[Link] && <span>Password must be 8+ characters</span>}
<button type="submit">Register</button>
</form>
);
}
Example 2: Complex Form with Watch and Dynamic Fields
import React from "react";
import { useForm, useFieldArray, Controller } from "react-hook-form";
function ComplexForm() {
const { register, control, watch, handleSubmit } = useForm({
defaultValues: {
addresses: [{ street: "", city: "" }],
},
});
const { fields, append, remove } = useFieldArray({
control,
name: "addresses",
});
// Only watch specific fields to minimize re-renders
const userType = watch("userType");
return (
<form onSubmit={handleSubmit(onSubmit)}>
<select {...register("userType")}>
<option value="individual">Individual</option>
<option value="business">Business</option>
</select>
{userType === "business" && (
<input {...register("companyName")} placeholder="Company Name" />
)}
<div>
<h3>Addresses</h3>
{[Link]((field, index) => (
<div key={[Link]}>
<input {...register(`addresses.${index}.street`)} />
<input {...register(`addresses.${index}.city`)} />
<button type="button" onClick={() => remove(index)}>
Remove
</button>
</div>
))}
<button type="button" onClick={() => append({ street: "", city: "" })}>
Add Address
</button>
</div>
<button type="submit">Submit</button>
</form>
);
}
Example 3: Form with Validation and Performance
import React from "react";
import { useForm } from "react-hook-form";
function LargeForm() {
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm({
mode: "onBlur", // Validate only on blur to minimize re-renders
reValidateMode: "onChange",
});
const onSubmit = async (data) => {
// Simulate API call
await new Promise((resolve) => setTimeout(resolve, 2000));
[Link]("Form submitted:", data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
{/* Form fields - uncontrolled, minimal re-renders */}
<input
{...register("firstName", {
required: "First name is required",
pattern: {
value: /^[a-zA-Z\s]*$/,
message: "Only letters and spaces allowed",
},
})}
/>
{[Link] && <span>{[Link]}</span>}
<textarea {...register("bio", { maxLength: 500 })} />
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? "Submitting..." : "Submit"}
</button>
</form>
);
}
Use Cases:
Large Forms: Forms with 50+ fields perform significantly better
Dynamic Fields: Forms with conditional fields and arrays
Async Validation: Real-time field validation with API calls
Multi-step Forms: Preserve state across form steps
Performance Impact:
70-90% fewer re-renders compared to controlled forms
Better performance with 100+ form fields
Significantly faster form interactions
Section 2 Summary Table: Ecosystem Libraries
Library Purpose Primary Benefit Performance Impact
RTK Query / API caching & Eliminates duplicate 50-70% fewer API
TanStack Query synchronization requests calls
Redux Persist State persistence Session preservation 100-500ms faster init
Prevents 10-20x selector
Reselect Memoized selectors
recalculations performance
Uncontrolled 70-90% fewer re-
React Hook Form Minimal re-renders
components renders
3. Webpack Performance Features
Webpack provides powerful tools for optimizing bundle size and loading performance.
Code Splitting
Overview: Code splitting divides your bundle into smaller chunks loaded on-demand.
Example 1: Dynamic Imports
// Traditional single bundle
import UserDashboard from "./pages/UserDashboard";
import AdminPanel from "./pages/AdminPanel";
import AnalyticsPage from "./pages/AnalyticsPage";
// Code-split version using dynamic imports
const UserDashboard = [Link](() => import("./pages/UserDashboard"));
const AdminPanel = [Link](() => import("./pages/AdminPanel"));
const AnalyticsPage = [Link](() => import("./pages/AnalyticsPage"));
// Only loads chunk when component is requested
Example 2: Webpack Configuration for Code Splitting
// [Link]
[Link] = {
mode: "production",
entry: "./src/[Link]",
output: {
path: [Link](__dirname, "dist"),
filename: "[name].[contenthash].js",
chunkFilename: "[name].[contenthash].[Link]",
},
optimization: {
splitChunks: {
chunks: "all",
cacheGroups: {
// Vendor libraries in separate chunk
vendor: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
priority: 10,
},
// Common code used by multiple chunks
common: {
minChunks: 2,
priority: 5,
reuseExistingChunk: true,
},
},
},
},
};
Example 3: Named Chunks for Better Debugging
// With webpack magic comments for better chunk names
const UserDashboard = [Link](
() =>
import(/* webpackChunkName: "user-dashboard" */ "./pages/UserDashboard"),
);
const AdminPanel = [Link](
() => import(/* webpackChunkName: "admin" */ "./pages/AdminPanel"),
);
// Generated chunks: user-dashboard.[hash].[Link], admin.[hash].[Link]
Use Cases:
Reducing initial bundle size by 50-70%
Faster initial page load
Better caching of unchanging code
Different bundle strategies for different user tiers
Performance Impact:
Initial load: 40-60% faster
Reduced Time to Interactive (TTI)
Better caching due to separate vendor chunks
Tree Shaking
Overview: Tree shaking removes unused code from your bundle through static analysis.
Example 1: Enabling Tree Shaking
// [Link]
[Link] = {
mode: "production", // Automatically enables tree shaking
optimization: {
usedExports: true, // Mark used exports
sideEffects: false, // No side effects, safe to remove
},
};
Example 2: Package Configuration for Tree Shaking
{
"name": "my-library",
"main": "dist/[Link]",
"module": "dist/esm/[Link]",
"sideEffects": ["*.css", "*.scss"],
"exports": {
".": {
"import": "./dist/esm/[Link]",
"require": "./dist/cjs/[Link]"
},
"./components": {
"import": "./dist/esm/[Link]",
"require": "./dist/cjs/[Link]"
}
}
}
Example 3: Writing Tree-Shakeable Code
// [Link] - All functions exported as named exports
export const formatDate = (date) => {
// Only included if imported
return new Date(date).toLocaleDateString();
};
export const calculateAge = (birthDate) => {
// Only included if imported
return new Date().getFullYear() - new Date(birthDate).getFullYear();
};
export const validateEmail = (email) => {
// Only included if imported
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
};
// Good: Only formatDate is bundled
import { formatDate } from "./utilities";
// Bad: Entire module is bundled even if unused functions exist
import * as utils from "./utilities";
Use Cases:
Removing unused dependencies from bundle
Eliminating dead code paths
Library authors providing efficient packages
Reducing bundle size by 10-30%
Performance Impact:
10-30% bundle size reduction
Better tree-shaking with ES modules
Faster JavaScript execution
Prefetch and Preload
Overview: Link prefetching and preloading hints tell browsers to load resources in advance.
Example 1: Prefetch for Future Navigation
<!-- Prefetch resources needed on next page -->
<link rel="prefetch" href="./pages/[Link]" />
<link rel="prefetch" href="./styles/[Link]" />
<link rel="prefetch" href="[Link] />
<!-- Low priority loading during idle time -->
Example 2: Preload for Critical Resources
<!-- Preload critical resources needed soon -->
<link
rel="preload"
href="./fonts/main-font.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<link rel="preload" href="./styles/[Link]" as="style" />
<link rel="preload" href="./images/[Link]" as="image" />
<!-- High priority loading immediately -->
Example 3: Smart Prefetching Based on User Input
import { useEffect } from "react";
function DashboardWithPrefetch() {
useEffect(() => {
// Prefetch next page on hover over a link
const links = [Link]("a[data-prefetch]");
[Link]((link) => {
[Link]("mouseenter", () => {
const href = [Link]("href");
const chunkName = [Link]("/")[1];
// Create link element for prefetch
const prefetchLink = [Link]("link");
[Link] = "prefetch";
[Link] = `./${chunkName}.[Link]`;
[Link](prefetchLink);
});
});
}, []);
return (
<nav>
<a href="/dashboard" data-prefetch>
Dashboard
</a>
<a href="/analytics" data-prefetch>
Analytics
</a>
</nav>
);
}
Use Cases:
Preloading fonts to prevent FOUT (Flash of Unstyled Text)
Prefetching predictable next page based on user flow
Preloading above-the-fold images
Prefetching API responses for likely user actions
Performance Impact:
Faster page transitions (200-500ms improvement)
Better user experience with reduced loading
Optimal network utilization
Webpack Magic Comments
Overview: Webpack magic comments are special inline comments in import() statements that control chunk
generation, loading strategy, and naming. They provide fine-grained control over how webpack processes dynamic
imports.
webpackChunkName
Purpose: Assigns a custom name to the generated chunk instead of auto-generated numeric identifiers.
Syntax: /* webpackChunkName: "name" */
Example 1: Basic Chunk Naming
// Without magic comment - generates: [Link]
const Dashboard = [Link](() => import("./pages/Dashboard"));
// With magic comment - generates: [Link]
const Dashboard = [Link](
() => import(/* webpackChunkName: "dashboard" */ "./pages/Dashboard"),
);
// Multiple imports can share the same chunk name
const UserProfile = [Link](
() => import(/* webpackChunkName: "user-pages" */ "./pages/UserProfile"),
);
const UserSettings = [Link](
() => import(/* webpackChunkName: "user-pages" */ "./pages/UserSettings"),
);
// Result: Creates a single chunk "[Link]" with both modules
Example 2: Chunk Naming in Routes
import React, { Suspense, lazy } from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
// Named chunks for better debugging and caching
const Home = lazy(
() => import(/* webpackChunkName: "home-page" */ "./pages/Home"),
);
const Products = lazy(
() => import(/* webpackChunkName: "products-page" */ "./pages/Products"),
);
const AdminDashboard = lazy(
() =>
import(/* webpackChunkName: "admin-dashboard" */ "./pages/AdminDashboard"),
);
const Checkout = lazy(
() => import(/* webpackChunkName: "checkout-flow" */ "./pages/Checkout"),
);
function App() {
return (
<BrowserRouter>
<Suspense fallback={<LoadingSpinner />}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products" element={<Products />} />
<Route path="/admin" element={<AdminDashboard />} />
<Route path="/checkout" element={<Checkout />} />
</Routes>
</Suspense>
</BrowserRouter>
);
}
// Generated chunks:
// - [Link]
// - [Link]
// - [Link]
// - [Link]
Use Cases:
More meaningful bundle names for debugging
Better browser cache busting strategy
Easier identification in network tab
Grouping related chunks together
webpackPrefetch
Purpose: Tells webpack to prefetch the chunk during idle time (low-priority prefetch).
Syntax: /* webpackPrefetch: true */
Behavior: Browser loads the chunk using <link rel="prefetch"> when it has idle time.
Example 1: Prefetch for Likely User Actions
function DashboardPage() {
const [showAdvanced, setShowAdvanced] = useState(false);
// Prefetch the advanced features module during idle time
const AdvancedFeatures = [Link](
() =>
import(
/* webpackChunkName: "advanced-features" */
/* webpackPrefetch: true */
"./components/AdvancedFeatures"
),
);
return (
<div>
<button onClick={() => setShowAdvanced(true)}>
Show Advanced Options
</button>
{showAdvanced && (
<Suspense fallback={<div>Loading...</div>}>
<AdvancedFeatures />
</Suspense>
)}
</div>
);
}
// Behavior:
// 1. Page loads normally with basic features
// 2. Browser prefetches advanced-features chunk during idle time
// 3. When user clicks button, chunk is already loaded
// 4. Component renders immediately without loading delay
Example 2: Prefetch Multiple Related Chunks
function ShoppingCart() {
const [step, setStep] = useState("review");
// Prefetch shipping and payment modules
const ShippingOptions = [Link](
() =>
import(
/* webpackChunkName: "shipping" */
/* webpackPrefetch: true */
"./checkout/Shipping"
),
);
const PaymentProcessor = [Link](
() =>
import(
/* webpackChunkName: "payment" */
/* webpackPrefetch: true */
"./checkout/Payment"
),
);
const OrderSummary = [Link](
() =>
import(
/* webpackChunkName: "order-summary" */
/* webpackPrefetch: true */
"./checkout/OrderSummary"
),
);
return (
<div>
{step === "review" && <ReviewCart />}
<Suspense fallback={<LoadingSpinner />}>
{step === "shipping" && <ShippingOptions />}
{step === "payment" && <PaymentProcessor />}
{step === "summary" && <OrderSummary />}
</Suspense>
<button onClick={() => setStep(nextStep)}>Next</button>
</div>
);
}
// Behavior:
// All checkout modules are prefetched during page load
// User experiences instant transitions between steps
Performance Impact:
Improves perceived performance by 300-500ms
Uses only idle network time (no impact on critical resources)
Best for user-predictable workflows
Use Cases:
Multi-step forms
Related features users likely access
Secondary pages with predictable navigation
Details views after list selection
webpackPreload
Purpose: Tells webpack to preload the chunk with high priority during page load.
Syntax: /* webpackPreload: true */
Behavior: Browser loads the chunk using <link rel="preload"> immediately (parallel to current script loading).
Example 1: Preload Critical Components
import React, { Suspense, lazy } from "react";
function App() {
// Preload the admin panel if user is admin (known immediately)
const AdminPanel = [Link](
() =>
import(
/* webpackChunkName: "admin-panel" */
/* webpackPreload: true */
"./pages/AdminPanel"
),
);
// Regular lazy load for normal users
const UserDashboard = [Link](
() =>
import(
/* webpackChunkName: "user-dashboard" */
"./pages/UserDashboard"
),
);
const user = useAuthContext();
return (
<Suspense fallback={<div>Loading...</div>}>
{[Link] === "admin" ? <AdminPanel /> : <UserDashboard />}
</Suspense>
);
}
// Behavior:
// For admin users, AdminPanel is preloaded immediately
// Resources load in parallel, reducing Time to Interactive
Example 2: Preload Above-the-Fold Critical Content
import React, { Suspense, lazy } from "react";
function HomePage() {
// Preload hero and featured sections that are immediately visible
const HeroSection = lazy(
() =>
import(
/* webpackChunkName: "hero" */
/* webpackPreload: true */
"./sections/Hero"
),
);
// Preload featured products (likely visible on scroll)
const FeaturedProducts = lazy(
() =>
import(
/* webpackChunkName: "featured" */
/* webpackPreload: true */
"./sections/FeaturedProducts"
),
);
// Regular lazy load for below-the-fold content
const Reviews = lazy(
() =>
import(
/* webpackChunkName: "reviews" */
"./sections/Reviews"
),
);
return (
<main>
<Suspense fallback={<div>Loading Hero...</div>}>
<HeroSection />
</Suspense>
<Suspense fallback={<div>Loading Products...</div>}>
<FeaturedProducts />
</Suspense>
<Suspense fallback={<div>Loading Reviews...</div>}>
<Reviews />
</Suspense>
</main>
);
}
// Behavior:
// Hero and Featured chunks load immediately and in parallel
// Reviews chunk loads on-demand when user scrolls down
Performance Impact:
Critical component instantly available
Better LCP (Largest Contentful Paint) scores
Use sparingly - too many preloads can hurt performance
When to Use:
High-priority user paths
Components required for meaningful page paint
Conditional rendering where both paths are equally likely
Critical interactive elements
Difference from webpackPrefetch: | Feature | webpackPrefetch | webpackPreload | |---------|-----------------|----------------| |
Priority | Low (idle time) | High (immediately) | | Browser Hint | <link rel="prefetch"> | <link rel="preload"> |
| Timing | After page resources load | Parallel to current loading | | Use Case | Optional features | Critical content |
webpackMode
Purpose: Controls how the module is used in the context of module concatenation (scope hoisting).
Syntax: /* webpackMode: "lazy" | "lazy-once" | "eager" | "weak" */
Example 1: Different Webpack Modes
// Mode: "lazy" (default)
// Each dynamic import creates a separate chunk
const ModuleA = () => import(/* webpackChunkName: "module-a" */ "./modules/A");
const ModuleB = () => import(/* webpackChunkName: "module-b" */ "./modules/B");
// Result: 2 separate chunks - [Link], [Link]
// Mode: "lazy-once"
// All dynamic imports in this statement share a single chunk
const dynamicModules = {
userProfile: () =>
import(
/* webpackChunkName: "lazy-module" */
/* webpackMode: "lazy-once" */
"./modules/UserProfile"
),
settings: () =>
import(
/* webpackChunkName: "lazy-module" */
/* webpackMode: "lazy-once" */
"./modules/Settings"
),
};
// Result: 1 shared chunk - [Link] (contains both modules)
// Mode: "eager"
// Includes module in main bundle, no separate chunk created
const CriticalModule = () =>
import(
/* webpackChunkName: "main" */
/* webpackMode: "eager" */
"./modules/Critical"
);
// Result: Module bundled with [Link]
// Mode: "weak"
// Requires module to exist as chunk, shared between entries
const SharedModule = () =>
import(
/* webpackMode: "weak" */
"./modules/Shared"
);
// Result: Assumes Shared chunk exists; doesn't create if missing
Example 2: Practical webpackMode Usage
function PluginSystem() {
// All plugins share a single chunk for efficiency
const plugins = {
analytics: () =>
import(
/* webpackChunkName: "plugins" */
/* webpackMode: "lazy-once" */
"./plugins/Analytics"
),
notifications: () =>
import(
/* webpackChunkName: "plugins" */
/* webpackMode: "lazy-once" */
"./plugins/Notifications"
),
reporting: () =>
import(
/* webpackChunkName: "plugins" */
/* webpackMode: "lazy-once" */
"./plugins/Reporting"
),
};
const [activePlugin, setActivePlugin] = useState("analytics");
const loadPlugin = async () => {
const Plugin = await plugins[activePlugin]();
return [Link];
};
return <div>{/* All plugins load from single chunk */}</div>;
}
webpackExports
Purpose: Specifies which exports to extract from a dynamic import, reducing chunk size.
Syntax: /* webpackExports: ["export1", "export2"] */
Example 1: Exporting Specific Functions
// utils/[Link]
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
export const multiply = (a, b) => a * b;
export const divide = (a, b) => a / b;
// [Link]
// Without webpackExports: Entire module bundled
const mathUtils = () => import("./utils/math");
// With webpackExports: Only needed exports included
const add = () =>
import(
/* webpackExports: ["add"] */
"./utils/math"
).then((module) => [Link]);
const calculator = () =>
import(
/* webpackExports: ["add", "multiply"] */
"./utils/math"
).then((module) => ({ add: [Link], multiply: [Link] }));
Example 2: Selective Component Imports
// components/[Link]
export const IconHome = () => <HomeIcon />;
export const IconUser = () => <UserIcon />;
export const IconSettings = () => <SettingsIcon />;
export const IconLogout = () => <LogoutIcon />;
// [Link]
// Only load necessary icons
const HeaderIcons = lazy(() =>
import(
/* webpackExports: ["IconHome", "IconUser"] */
"./components/Icons"
).then((module) => ({
default: () => (
<>
<[Link] />
<[Link] />
</>
),
})),
);
// Only load settings icon when admin panel opens
const AdminIcons = lazy(() =>
import(
/* webpackExports: ["IconSettings", "IconLogout"] */
"./components/Icons"
).then((module) => ({
default: () => (
<>
<[Link] />
<[Link] />
</>
),
})),
);
webpackInclude and webpackExclude
Purpose: Filter dynamic imports using regex patterns (for dynamic import expressions).
Syntax: /* webpackInclude: /pattern/ */ and /* webpackExclude: /pattern/ */
Example 1: Dynamic Imports with Filtering
// Dynamic import based on user locale
function LocalizedApp({ locale }) {
// Only includes files matching the pattern
const i18n = () =>
import(
/* webpackInclude: /i18n/ */
/* webpackExclude: /test/ */
`./locales/${locale}.js`
);
return i18n().then((module) => [Link]);
}
// Without regex: would try to bundle entire filesystem
// With regex: only bundles ./locales/ files
Example 2: Feature Module Filtering
// Load feature modules dynamically
async function loadFeature(featureName) {
const Feature = await import(
/* webpackInclude: /features/ */
/* webpackExclude: /(deprecated|beta)/ */
`./features/${featureName}.js`
);
return [Link];
}
// Includes: all files in ./features/
// Excludes: files containing "deprecated" or "beta"
Combining Multiple Magic Comments
Example 1: Complete Example with Multiple Comments
function OptimizedApp() {
// Multiple magic comments for fine-grained control
const AdminDashboard = lazy(
() =>
import(
/* webpackChunkName: "admin" */ // Named chunk
/* webpackPrefetch: true */ // Prefetch when idle
/* webpackMode: "lazy" */ // Standard lazy loading
"./pages/AdminDashboard"
),
);
const UserProfile = lazy(
() =>
import(
/* webpackChunkName: "user-profile" */ // Named chunk
/* webpackPreload: true */ // Preload immediately
/* webpackMode: "eager" */ // Include in main bundle
"./pages/UserProfile"
),
);
const HeavyChart = lazy(
() =>
import(
/* webpackChunkName: "charts" */ // Named chunk
/* webpackPrefetch: true */ // Prefetch when idle
/* webpackExports: ["BarChart"] */ // Only import specific export
"./components/Charts"
),
);
return (
<Suspense fallback={<LoadingSpinner />}>
<Routes>
<Route path="/admin" element={<AdminDashboard />} />
<Route path="/profile" element={<UserProfile />} />
<Route path="/analytics" element={<HeavyChart />} />
</Routes>
</Suspense>
);
}
Example 2: Real-World E-commerce Application
function EcommerceApp() {
// Critical paths - preload
const ProductList = lazy(
() =>
import(
/* webpackChunkName: "products" */
/* webpackPreload: true */
"./pages/Products"
),
);
const ProductDetail = lazy(
() =>
import(
/* webpackChunkName: "product-detail" */
/* webpackPreload: true */
"./pages/ProductDetail"
),
);
// Likely paths - prefetch
const Cart = lazy(
() =>
import(
/* webpackChunkName: "cart" */
/* webpackPrefetch: true */
"./pages/Cart"
),
);
const Checkout = lazy(
() =>
import(
/* webpackChunkName: "checkout" */
/* webpackPrefetch: true */
"./pages/Checkout"
),
);
// Optional features - lazy load only
const ReviewSection = lazy(
() =>
import(
/* webpackChunkName: "reviews" */
"./components/Reviews"
),
);
const RecommendedProducts = lazy(
() =>
import(
/* webpackChunkName: "recommendations" */
"./components/Recommendations"
),
);
return (
<Suspense fallback={<LoadingSpinner />}>
<Routes>
<Route path="/products" element={<ProductList />} />
<Route path="/product/:id" element={<ProductDetail />} />
<Route path="/cart" element={<Cart />} />
<Route path="/checkout" element={<Checkout />} />
</Routes>
<ReviewSection />
<RecommendedProducts />
</Suspense>
);
}
// Loading strategy:
// 1. Initial load: ProductList, ProductDetail preloaded
// 2. Idle time: Cart, Checkout prefetched
// 3. On demand: ReviewSection, Recommendations loaded
Magic Comments Reference Table
Comment Syntax Purpose Priority Use Case
/* webpackChunkName: Custom chunk Debugging,
webpackChunkName "name" */ -
naming caching
/* webpackPrefetch: true Low-priority Optional
webpackPrefetch Low
*/ prefetch features
/* webpackPreload: true High-priority Critical
webpackPreload High
*/ preload components
/* webpackMode: "lazy" Module resolution Bundle
webpackMode -
*/ mode optimization
Comment Syntax Purpose Priority Use Case
/* webpackExports:
webpackExports ["export"] */ Selective exports - Tree-shaking
/* webpackInclude: Include filter Dynamic
webpackInclude -
/pattern/ */ (regex) imports
/* webpackExclude: Exclude filter Dynamic
webpackExclude -
/pattern/ */ (regex) imports
Best Practices for Webpack Magic Comments
1. Use Descriptive Names: Make chunk names meaningful and consistent
// Good
import(/* webpackChunkName: "user-profile" */ "./pages/UserProfile");
// Bad
import(/* webpackChunkName: "p1" */ "./pages/UserProfile");
2. Balance Preload and Prefetch: Too many preloads can hurt performance
// Good: Only preload truly critical
const Critical = lazy(() => import(/* webpackPreload: true */ "./Critical"));
// Bad: Excessive preloading
const Everything = lazy(() => import(/* webpackPreload: true */ "./Heavy"));
3. Group Related Modules: Use shared chunk names to group related functionality
const Admin1 = lazy(
() => import(/* webpackChunkName: "admin" */ "./AdminUser"),
);
const Admin2 = lazy(
() => import(/* webpackChunkName: "admin" */ "./AdminSettings"),
);
// Combines into single admin chunk
4. Monitor Bundle Size: Use webpack-bundle-analyzer to verify chunk sizes
// Use consistent chunking strategy
// Verify generated chunks match expectations
5. Test Performance Impact: Measure actual impact before and after
// Before: No magic comments - multiple small chunks
// After: With magic comments - optimized loading strategy
Section 3 Summary Table: Webpack Performance Features
& Magic Comments
Feature Type Purpose Performance Impact
Code Splitting Webpack Reduce initial bundle 40-60% faster initial load
Remove unused
Tree Shaking Webpack 10-30% bundle reduction
code
Prefetch Link Hint Low-priority loading 200-500ms faster transitions
Preload Link Hint High-priority loading Better LCP scores
Magic
webpackChunkName Named chunks Better debugging & caching
Comment
Magic
webpackPrefetch Idle-time prefetch 300-500ms improvement
Comment
Magic
webpackPreload Immediate preload Critical content ready
Comment
Magic
webpackMode Module resolution Optimized bundling
Comment
Magic
webpackExports Selective exports Reduced chunk size
Comment
4. Performance Metrics
Understanding and monitoring performance metrics is crucial for optimization.
Core Web Vitals
LCP (Largest Contentful Paint)
Measures: When the largest content element becomes visible
Target: < 2.5 seconds
What to Optimize: Image optimization, code splitting, server response time
Example: Optimizing LCP
// Unoptimized: Large hero image causes slow LCP
function HeroSection() {
return (
<img
src="/images/[Link]" // Large unoptimized image
alt="Hero"
style={{ width: "100%" }}
/>
);
}
// Optimized: Multiple strategies
function HeroSection() {
return (
<img
src="/images/[Link]" // Modern format
srcSet="/images/[Link] 600w, /images/[Link] 1200w"
alt="Hero"
loading="eager" // Preload above-fold image
fetchPriority="high"
style={{ width: "100%" }}
/>
);
}
INP (Interaction to Next Paint)
Measures: Time from user input to visible response
Target: < 200 milliseconds
What to Optimize: Event handler performance, reduce main thread blocking
Example: Optimizing INP
// Unoptimized: Heavy calculation blocks interaction response
function SearchResults() {
const [query, setQuery] = useState("");
const handleSearch = (e) => {
const value = [Link];
// Heavy calculation blocks input response
const results = heavyFilter(value);
setQuery(value);
};
return <input onChange={handleSearch} />;
}
// Optimized: Defer heavy work
function SearchResults() {
const [query, setQuery] = useState("");
const [isPending, startTransition] = useTransition();
const handleSearch = (e) => {
const value = [Link];
setQuery(value); // Immediate UI update
// Defer heavy work
startTransition(() => {
performSearch(value);
});
};
return <input onChange={handleSearch} disabled={isPending} />;
}
CLS (Cumulative Layout Shift)
Measures: Unexpected layout shifts
Target: < 0.1
What to Optimize: Reserve space for dynamic content, animations
Example: Preventing Layout Shifts
// Unoptimized: Layout shifts when content loads
function Article() {
const [imageLoaded, setImageLoaded] = useState(false);
return (
<div>
<h1>Article Title</h1>
<img
onLoad={() => setImageLoaded(true)}
src="/[Link]"
alt="Article"
/>
{imageLoaded && <p>Image description</p>}
</div>
);
}
// Optimized: Reserve space to prevent shifts
function Article() {
return (
<div>
<h1>Article Title</h1>
{/* Reserve space with aspect ratio */}
<div style={{ aspectRatio: "16/9", background: "#f0f0f0" }}>
<img
src="/[Link]"
alt="Article"
style={{ width: "100%", height: "100%", objectFit: "cover" }}
/>
</div>
<p>Image description</p>
</div>
);
}
Additional Metrics
TTI (Time to Interactive)
First time page becomes fully interactive
Optimize by reducing JavaScript and using code splitting
TBT (Total Blocking Time)
Total time main thread is blocked (>50ms tasks)
Optimize by breaking long tasks into smaller chunks
Example: Measuring Performance Metrics
import { getCLS, getFCP, getFID, getLCP, getTTFB } from "web-vitals";
// Report all metrics
getCLS([Link]); // CLS
getFCP([Link]); // FCP
getFID([Link]); // FID (deprecated, use INP)
getLCP([Link]); // LCP
getTTFB([Link]); // TTFB
// Custom metric reporting
function reportWebVitals(metric) {
[Link](metric);
// Send to analytics
if ([Link]) {
[Link]("/analytics", [Link](metric));
}
}
getLCP(reportWebVitals);
getINP(reportWebVitals);
getCLS(reportWebVitals);
Section 4 Summary Table: Performance Metrics & Core
Web Vitals
Metric Measures Target What to Optimize
LCP (Largest Contentful Loading Image optimization, code
< 2.5s
Paint) performance splitting
INP (Interaction to Next <
Responsiveness Event handler performance
Paint) 200ms
CLS (Cumulative Layout
Visual stability < 0.1 Reserved space, animations
Shift)
TTI (Time to Interactive) Page interactivity < 3.8s Reduce JavaScript, code split
Main thread <
TBT (Total Blocking Time) Break long tasks
blocking 300ms
FCP (First Contentful Paint) First render < 1.8s Prioritize critical resources
< Optimize server, enable
TTFB (Time to First Byte) Server response
600ms caching
5. Class-Only Functionalities
Certain React features are only available in class components.
Error Boundaries
Overview: Error Boundaries catch JavaScript errors anywhere in the component tree and display a fallback UI.
Example 1: Basic Error Boundary
class ErrorBoundary extends [Link] {
constructor(props) {
super(props);
[Link] = { hasError: false, error: null };
}
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
[Link]("Error caught:", error, errorInfo);
// Send to error tracking service
[Link](error, errorInfo);
}
render() {
if ([Link]) {
return (
<div style={{ padding: "20px", border: "1px solid red" }}>
<h2>Something went wrong</h2>
<p>{[Link]?.message}</p>
<button onClick={() => [Link]({ hasError: false })}>
Try again
</button>
</div>
);
}
return [Link];
}
}
// Usage
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>;
Example 2: Granular Error Boundaries
class ErrorBoundary extends [Link] {
constructor(props) {
super(props);
[Link] = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
render() {
if ([Link]) {
return <h2>Section Error: Failed to load this component</h2>;
}
return [Link];
}
}
function App() {
return (
<div>
<Header />
<ErrorBoundary>
<Sidebar />
</ErrorBoundary>
<ErrorBoundary>
<MainContent />
</ErrorBoundary>
<ErrorBoundary>
<Footer />
</ErrorBoundary>
</div>
);
}
getSnapshotBeforeUpdate
Overview: Called right before DOM mutations, used to capture information from the DOM (like scroll position).
Example 1: Preserving Scroll Position
class ScrollPreservingList extends [Link] {
constructor(props) {
super(props);
[Link] = [Link]();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// Capture scroll position before items change
if ([Link] < [Link]) {
return [Link] - [Link];
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// Restore scroll position after items change
if (snapshot !== null) {
[Link] =
[Link] - snapshot;
}
}
render() {
return (
<ul ref={[Link]}>
{[Link]((item) => (
<li key={[Link]}>{[Link]}</li>
))}
</ul>
);
}
}
Example 2: Capturing Element Dimensions
class ResponsiveComponent extends [Link] {
getSnapshotBeforeUpdate(prevProps, prevState) {
// Capture current dimensions before content change
return {
width: [Link],
height: [Link],
};
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (snapshot) {
const { width, height } = snapshot;
[Link](`Previous dimensions: ${width}x${height}`);
}
}
render() {
return <div ref={(el) => ([Link] = el)}>{[Link]}</div>;
}
}
Section 5 Summary Table: Class-Only Functionalities
Feature Purpose When to Use Key Method/Property
Catch runtime Graceful error
Error Boundaries getDerivedStateFromError()
errors handling
Track and report
componentDidCatch Error logging componentDidCatch()
errors
Capture DOM Preserve scroll
getSnapshotBeforeUpdate getSnapshotBeforeUpdate()
state position
Post-update Apply snapshot
componentDidUpdate componentDidUpdate()
actions changes
6. [Link] vs
shouldComponentUpdate
Understanding the Differences
shouldComponentUpdate (Class Components)
Manually control whether component should re-render
Returns boolean
Called before render
[Link] (Functional Components)
HOC for shallow prop comparison
Prevents re-render if props haven't changed
Similar to PureComponent
Example 1: shouldComponentUpdate in Class Components
class UserProfile extends [Link] {
shouldComponentUpdate(nextProps, nextState) {
// Only re-render if specific props change
return (
[Link] !== [Link] ||
[Link] !== [Link] ||
[Link] !== [Link]
);
}
render() {
return <div>{[Link]}</div>;
}
}
Example 2: [Link] with Functional Component
// Basic [Link] - shallow comparison
const UserProfile = [Link](function UserProfile({ userId, theme }) {
return <div>{userId}</div>;
});
// Re-renders only if userId or theme changes (shallow comparison)
Example 3: Custom Comparison with [Link]
const UserProfile = [Link](
function UserProfile({ user, settings }) {
return <div>{[Link]}</div>;
},
(prevProps, nextProps) => {
// Custom comparison logic
// Return true if props are equal (skip re-render)
// Return false if props changed (re-render)
return (
[Link] === [Link] &&
[Link] === [Link]
);
},
);
Section 6 Summary Table: [Link] vs
shouldComponentUpdate
Component
Feature Comparison Use Case
Type
Complex comparison
shouldComponentUpdate Class Manual control
logic
Shallow
[Link] Functional Simple prop checks
comparison
Nested object/array
Custom Comparison Both Deep comparison
props
Shallow Comparison Both First-level only Most common scenario
7. Pure Component vs Functional
Component
Comparison and Usage
PureComponent
Performs shallow prop/state comparison
Prevents unnecessary re-renders
Only for class components
Functional Components with [Link]
Similar behavior to PureComponent
Modern approach
Requires explicit memoization
Example 1: PureComponent
class User extends [Link] {
render() {
// PureComponent automatically compares props
// Skips render if props unchanged
return <div>{[Link]}</div>;
}
}
Example 2: Functional Component with [Link]
const User = [Link](function User({ name }) {
return <div>{name}</div>;
});
// Equivalent behavior to PureComponent
Example 3: Performance Comparison
// Without optimization - renders on every parent update
function UserListItem({ user }) {
[Link]("Rendering:", [Link]);
return <div>{[Link]}</div>;
}
// With PureComponent - prevents unnecessary renders
class UserListItem extends [Link] {
render() {
[Link]("Rendering:", [Link]);
return <div>{[Link]}</div>;
}
}
// With [Link] - prevents unnecessary renders
const UserListItemMemo = [Link](function UserListItem({ user }) {
[Link]("Rendering:", [Link]);
return <div>{[Link]}</div>;
});
// Usage comparison
function UserList({ users }) {
return (
<div>
{[Link]((user) => (
<UserListItemMemo key={[Link]} user={user} />
))}
</div>
);
}
Section 7 Summary Table: Pure Component vs Functional
Component
Functional +
Aspect PureComponent Winner
[Link]
Type Class component Functional component Functional (modern)
Automatic
Comparison Manual shallow PureComponent (built-in)
shallow
Boilerplate More Less Functional
Performance Good Good Same
Modern
Legacy Recommended Functional
Approach
Functional +
Aspect PureComponent Winner
[Link]
With Hooks N/A Yes Functional
Example 4: Custom Comparison Function in [Link] (shouldComponentUpdate-like Functionality)
// Functional component with custom [Link] comparison
// This is equivalent to shouldComponentUpdate in class components
const UserProfile = [Link](
function UserProfile({ userId, userData, settings, theme }) {
return (
<div style={{ background: theme === "dark" ? "#222" : "#fff" }}>
<h1>{[Link]}</h1>
<p>Role: {[Link]}</p>
<p>Language: {[Link]}</p>
</div>
);
},
// Custom comparison function (second argument)
// Similar to shouldComponentUpdate
(prevProps, nextProps) => {
// Return true if props are EQUAL (skip re-render)
// Return false if props are DIFFERENT (re-render)
// Only re-render if userId or userData changes
// Ignore settings and theme changes
return (
[Link] === [Link] &&
[Link]?.id === [Link]?.id &&
[Link]?.name === [Link]?.name
);
},
);
// Usage
function App() {
const [userId, setUserId] = useState(1);
const [settings, setSettings] = useState({ role: "user", language: "en" });
const [theme, setTheme] = useState("light");
return (
<>
<UserProfile
userId={userId}
userData={{ id: userId, name: "John" }}
settings={settings} // Changes won't trigger re-render
theme={theme} // Changes won't trigger re-render
/>
<button onClick={() => setSettings({ ...settings, language: "es" })}>
Change Language (no re-render)
</button>
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
Toggle Theme (no re-render)
</button>
<button onClick={() => setUserId(userId + 1)}>
Change User (triggers re-render)
</button>
</>
);
}
Comparison with Class Component shouldComponentUpdate:
// Class component equivalent with shouldComponentUpdate
class UserProfile extends [Link] {
shouldComponentUpdate(nextProps, nextState) {
// Return true to re-render, false to skip
return (
[Link] !== [Link] ||
[Link]?.id !== [Link]?.id ||
[Link]?.name !== [Link]?.name
);
}
render() {
return (
<div
style={{ background: [Link] === "dark" ? "#222" : "#fff" }}
>
<h1>{[Link]}</h1>
<p>Role: {[Link]}</p>
<p>Language: {[Link]}</p>
</div>
);
}
}
Key Differences in Comparison Logic:
[Link] custom function: Return true to SKIP re-render (props are equal)
shouldComponentUpdate: Return true to PERFORM re-render (props are different)
This is the inverse logic - be careful not to mix them up!
Advanced Example: Comparing Complex Objects
const ComplexComponent = [Link](
({ user, preferences, theme }) => {
return (
<div>
{[Link]} -{" "}
{[Link] ? "Notifications ON" : "Notifications OFF"}
</div>
);
},
(prevProps, nextProps) => {
// Deep comparison for nested objects
const userEqual =
[Link]?.id === [Link]?.id &&
[Link]?.email === [Link]?.email;
const preferencesEqual =
[Link]?.notifications ===
[Link]?.notifications &&
[Link]?.theme === [Link]?.theme;
// Return true if all important props are equal (skip re-render)
return userEqual && preferencesEqual;
// Note: theme prop is not compared, so its changes are ignored
},
);
8. JavaScript Expression Execution &
Coercion
Understanding JavaScript's type coercion is crucial for avoiding bugs and optimizing comparisons.
Implicit Type Coercion Rules
Example 1: Numeric Coercion
// Type coercion in comparisons
[Link](1 + 1 + 1 > 1 + 1 > 1); // false
// Breakdown: (1+1+1) > (1+1) > 1
// 3 > 2 > 1
// true > 1
// 1 > 1 → false
[Link](1 + 1 + 1 > 1 + 1); // true
// 3 > 2 → true
[Link](1 + 1 > 1); // true
// 2 > 1 → true
Example 2: Array Coercion
[Link]([] == ![]); // true
// Breakdown:
// ![] → false (array is truthy, negation makes it falsy)
// [] == false
// [] → 0 (empty array coerces to 0)
// 0 == false
// false → 0
// 0 == 0 → true
[Link]([] == false); // true
[Link]([] == 0); // true
[Link]([] == ""); // true
Example 3: String Concatenation with Type Coercion
[Link](1 + 2 + "3" + 4); // '334'
// Breakdown:
// 1 + 2 → 3 (numeric addition)
// 3 + '3' → '33' (string concatenation)
// '33' + 4 → '334' (string concatenation)
[Link]("1" + 2 + 3); // '123'
// '1' + 2 → '12' (string concatenation)
// '12' + 3 → '123'
[Link](1 + "2" + 3); // '123'
// 1 + '2' → '12' (string concatenation)
// '12' + 3 → '123'
Example 4: Truthy and Falsy Values
// Falsy values: false, 0, -0, 0n, '', null, undefined, NaN
// Truthy values: everything else
// Common coercion patterns
if (value) {
} // value is truthy
if (!value) {
} // value is falsy
// Comparisons
0 == false; // true
0 === false; // false
"" == false; // true
"" === false; // false
null == undefined; // true
null === undefined; // false
NaN == NaN; // false
NaN === NaN; // false
Example 5: Optimizing Comparisons
// Avoid implicit coercion - use strict comparison
function processValue(value) {
// Bad: relies on type coercion
if (value) {
// Treats 0, '', false as same
[Link]("truthy");
}
// Good: explicit checks
if (value !== null && value !== undefined) {
[Link]("value exists");
}
// Better: use nullish coalescing
const safeValue = value ?? "default";
// Or optional chaining
const nested = value?.property?.deeply?.nested;
}
// Performance optimization
function fastComparison(a, b) {
// Faster than dynamic type coercion
return a === b; // Strict comparison, no coercion
}
// Avoid expensive coercions
const numbers = [Link]((item) => item > 0); // Fast
const numbers2 = [Link]((item) => Boolean(item)); // Slower due to function call
Practical Performance Implications
// Type coercion can cause unexpected performance issues
// Example: Array equality checks
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
[Link](arr1 == arr2); // false (different objects)
[Link](arr1 === arr2); // false
// Both require comparison, but === is faster (no coercion)
// Optimization: Use Set for faster lookups
const lookupSet = new Set([1, 2, 3]);
[Link]([Link](2)); // true (O(1) lookup)
// String comparison with coercion
const value = "123";
[Link](value == 123); // true (coercion required)
[Link](value === 123); // false (no coercion)
// === is faster as no type coercion needed
Section 8 Summary Table: JavaScript Type Coercion & Best
Practices
Concept Example Result Best Practice
Numeric Coercion 1+1+1 > 1+1 > 1 false Use parentheses for clarity
Array Coercion [] == ![] true Avoid == comparisons
String Concatenation 1 + 2 + '3' + 4 '334' Be explicit with types
Falsy Values 0, '', null, NaN false Use === for strict checks
Truthy Values Non-falsy values true Explicit boolean checks
Comparison Performance === vs == === faster Always use strict equality
Avoid Type Coercion Use strict === Predictable Faster execution
Summary and Best Practices
Performance Optimization Checklist
1. Use React 18+ for automatic batching and transitions
2. Implement Code Splitting with [Link]() and Suspense
3. Leverage useMemo and useCallback for expensive operations
4. Use [Link] for functional components to prevent unnecessary re-renders
5. Implement RTK Query or TanStack Query for efficient data fetching
6. Monitor Core Web Vitals (LCP, INP, CLS)
7. Use Webpack features: tree-shaking, code splitting, prefetch/preload
8. Avoid type coercion by using strict comparisons (===)
9. Profile applications using React DevTools and Chrome DevTools
Performance Metrics Goals
Metric Target
LCP < 2.5s
INP < 200ms
CLS < 0.1
TTI < 3.8s
FCP < 1.8s
Tools for Performance Analysis
React DevTools Profiler: Measure component render times
Chrome DevTools: Network, Performance, and Lighthouse tabs
Web Vitals: npm package for measuring Core Web Vitals
Webpack Bundle Analyzer: Visualize bundle composition
Lighthouse: Automated performance audits
9. Web Workers & Service Workers
Web Workers and Service Workers are powerful APIs for handling background tasks and managing large datasets
without blocking the main thread.
Web Workers: Background Processing
Overview: Web Workers run JavaScript code in background threads, separate from the main UI thread, allowing CPU-
intensive tasks to be processed without freezing the user interface.
Key Characteristics:
Run in separate thread from main UI thread
Cannot access DOM or modify UI directly
Communicate via message passing
Dedicated to a single origin
Perfect for heavy computations
Example 1: Basic Web Worker Setup
// [Link] - Worker script file
[Link] = function (event) {
const data = [Link];
// Perform expensive computation
[Link]("Worker received:", data);
// Send result back to main thread
[Link]({
result: [Link]((a, b) => a + b, 0),
squared: [Link]((n) => n * n),
});
};
// [Link] - Main React component
import React, { useState } from "react";
function DataProcessor() {
const [result, setResult] = useState(null);
const [isProcessing, setIsProcessing] = useState(false);
const handleProcess = () => {
setIsProcessing(true);
// Create worker instance
const worker = new Worker("/[Link]");
// Send large dataset to worker
const largeDataset = {
numbers: [Link]({ length: 1000000 }, (_, i) => i),
};
[Link](largeDataset);
// Handle worker response
[Link] = (event) => {
setResult([Link]);
setIsProcessing(false);
[Link](); // Clean up worker
};
// Handle worker errors
[Link] = (error) => {
[Link]("Worker error:", [Link]);
setIsProcessing(false);
};
};
return (
<div>
<button onClick={handleProcess} disabled={isProcessing}>
{isProcessing ? "Processing..." : "Process Large Dataset"}
</button>
{result && (
<div>
<p>Sum: {[Link]}</p>
<p>Squared: {[Link](0, 5).join(", ")}...</p>
</div>
)}
</div>
);
}
Example 2: Web Worker for Image Processing
// [Link] - Image processing worker
[Link] = function (event) {
const { imageData } = [Link];
// Heavy image processing (grayscale conversion)
const data = [Link];
for (let i = 0; i < [Link]; i += 4) {
const gray = data[i] * 0.299 + data[i + 1] * 0.587 + data[i + 2] * 0.114;
data[i] = gray; // Red
data[i + 1] = gray; // Green
data[i + 2] = gray; // Blue
// data[i + 3] is alpha, leave unchanged
}
[Link]({ processedImageData: imageData });
};
// [Link]
function ImageProcessor() {
const canvasRef = useRef();
const [isProcessing, setIsProcessing] = useState(false);
const handleProcessImage = async () => {
setIsProcessing(true);
const canvas = [Link];
const ctx = [Link]("2d");
const imageData = [Link](0, 0, [Link], [Link]);
const worker = new Worker("/[Link]");
[Link]({ imageData });
[Link] = (event) => {
[Link]([Link], 0, 0);
setIsProcessing(false);
[Link]();
};
};
return (
<div>
<canvas ref={canvasRef} width={800} height={600} />
<button onClick={handleProcessImage} disabled={isProcessing}>
Convert to Grayscale
</button>
</div>
);
}
Example 3: Persistent Worker Pool
// [Link] - Reusable worker pool
class WorkerPool {
constructor(workerScript, poolSize = 4) {
[Link] = [];
[Link] = [];
[Link] = new Set();
// Create pool of workers
for (let i = 0; i < poolSize; i++) {
const worker = new Worker(workerScript);
[Link] = (event) => [Link](worker, event);
[Link](worker);
}
}
async execute(data) {
return new Promise((resolve, reject) => {
const task = { data, resolve, reject };
const availableWorker = [Link](
(w) => ,
);
if (availableWorker) {
[Link](availableWorker, task);
} else {
[Link](task);
}
});
}
executeTask(worker, task) {
[Link](worker);
[Link] = task;
[Link]([Link]);
}
handleWorkerComplete(worker, event) {
const { resolve } = [Link];
resolve([Link]);
[Link](worker);
if ([Link] > 0) {
const nextTask = [Link]();
[Link](worker, nextTask);
}
}
terminate() {
[Link]((w) => [Link]());
}
}
// Usage in React component
function DataProcessingApp() {
const poolRef = useRef(null);
const [results, setResults] = useState([]);
useEffect(() => {
[Link] = new WorkerPool("/[Link]", 4);
return () => [Link]?.terminate();
}, []);
const processMultipleDatasets = async () => {
const datasets = [
{ numbers: [1, 2, 3, 4, 5] },
{ numbers: [6, 7, 8, 9, 10] },
{ numbers: [11, 12, 13, 14, 15] },
];
const promises = [Link]((data) => [Link](data));
const allResults = await [Link](promises);
setResults(allResults);
};
return (
<div>
<button onClick={processMultipleDatasets}>
Process Multiple Datasets
</button>
{[Link]((r, i) => (
<div key={i}>
Result {i}: {[Link]}
</div>
))}
</div>
);
}
Use Cases:
Heavy data processing and transformations
Image/video processing
JSON parsing of large files
Cryptographic operations
Complex calculations
Regular expression matching on large strings
Performance Impact:
Prevents UI thread blocking
30-50% improvement in UI responsiveness
Better user experience during heavy tasks
Service Workers: Caching & Offline Support
Overview: Service Workers are special workers that act as a proxy between web app and network, enabling offline
functionality, caching strategies, and background sync.
Key Characteristics:
Persists between sessions
Can intercept network requests
Enable offline functionality
Handle push notifications
Control caching strategy
Single worker per scope
Example 1: Basic Service Worker Registration
// [Link] - Register service worker
import { useEffect } from "react";
function App() {
useEffect(() => {
if ("serviceWorker" in navigator) {
[Link]
.register("/[Link]")
.then((registration) => {
[Link]("Service Worker registered:", registration);
})
.catch((error) => {
[Link]("Service Worker registration failed:", error);
});
}
}, []);
return <div>App with Service Worker</div>;
}
// [Link] - Service worker script
const CACHE_NAME = "app-cache-v1";
const URLS_TO_CACHE = ["/", "/[Link]", "/[Link]", "/[Link]"];
// Install event - cache resources
[Link]("install", (event) => {
[Link](
caches
.open(CACHE_NAME)
.then((cache) => [Link](URLS_TO_CACHE))
.then(() => [Link]()),
);
});
// Activate event - clean old caches
[Link]("activate", (event) => {
[Link](
caches
.keys()
.then((cacheNames) => {
return [Link](
[Link]((cacheName) => {
if (cacheName !== CACHE_NAME) {
return [Link](cacheName);
}
}),
);
})
.then(() => [Link]()),
);
});
// Fetch event - serve from cache, fallback to network
[Link]("fetch", (event) => {
if ([Link] !== "GET") {
return; // Only cache GET requests
}
[Link](
[Link]([Link]).then((response) => {
if (response) {
return response; // Serve from cache
}
return fetch([Link])
.then((response) => {
// Don't cache non-successful responses
if (
!response ||
[Link] !== 200 ||
[Link] === "error"
) {
return response;
}
// Cache successful responses
const responseToCache = [Link]();
[Link](CACHE_NAME).then((cache) => {
[Link]([Link], responseToCache);
});
return response;
})
.catch(() => {
// Offline fallback
return [Link]("/[Link]");
});
}),
);
});
Example 2: Stale-While-Revalidate Strategy
// [Link] - Advanced caching strategy
[Link]("fetch", (event) => {
// Stale-While-Revalidate: Serve from cache immediately,
// then update cache in background
[Link](
[Link]([Link]).then((cachedResponse) => {
// Serve cached response immediately
const fetchPromise = fetch([Link]).then((response) => {
// Update cache with new response
if ([Link] === 200) {
const responseToCache = [Link]();
caches
.open("dynamic-cache")
.then((cache) => [Link]([Link], responseToCache));
}
return response;
});
// Return cached response if available, otherwise wait for fetch
return cachedResponse || fetchPromise;
}),
);
});
Example 3: Background Sync with Service Worker
// [Link] - Background sync
[Link]("sync", (event) => {
if ([Link] === "sync-data") {
[Link](
// Retry syncing data when connection is restored
fetch("/api/sync", { method: "POST" })
.then((response) => [Link]())
.then((data) => {
// Notify all clients about sync completion
[Link]().then((clients) => {
[Link]((client) => {
[Link]({
type: "SYNC_COMPLETE",
data: data,
});
});
});
})
.catch((error) => {
[Link]("Sync failed:", error);
throw error; // Retry sync
}),
);
}
});
Use Cases:
Offline-first applications
Caching strategy management
Background sync when connection is restored
Push notifications
Reducing network traffic
Faster app loading
Performance Impact:
50-80% faster page loads with caching
Works completely offline
Reduces bandwidth usage significantly
Comparison: Web Workers vs Service Workers
Aspect Web Workers Service Workers
Aspect Web Workers Service Workers
Purpose Background computations Caching & network management
Thread Separate thread Separate thread
Lifetime Tied to creating page Persists across sessions
DOM Access No No
Network Interception No Yes
Offline Support No Yes
Number Per App Multiple One per scope
Communication Message passing Message passing, sync events
CPU Tasks ✓ Heavy computations ✗ Not designed
Caching ✗ Not designed ✓ Cache API
Push Notifications ✗ ✓
Background Sync ✗ ✓
Browser Support ~95% ~88%
Section 9 Summary Table: Web Workers & Service Workers
Decision Guide
Scenario Best Choice Reason
Large data processing Web Worker Offload CPU work from main thread
Heavy computation without UI
Image/video processing Web Worker
blocking
Offline functionality Service Worker Cache and serve offline
Network optimization Service Worker Control caching strategy
Complex calculations Web Worker Math operations, sorting, filtering
API response caching Service Worker Intercept and cache requests
Background sync Service Worker Retry when connection restored
Web Worker + Service
Real-time collaboration Workers for sync, SW for offline
Worker
JSON parsing (large
Web Worker Prevent UI freeze
files)
Enable notifications when app
Push notifications Service Worker
closed
Data transformation Web Worker ETL operations
Progressive
Service Worker Enhance with offline support
enhancement
Best Practices for Web Workers:
1. Use worker pools for multiple concurrent tasks
2. Keep messages small to reduce communication overhead
3. Always terminate workers when done
4. Handle errors with onerror handlers
5. Consider worker creation overhead for small tasks
Best Practices for Service Workers:
1. Implement version-based cache invalidation
2. Provide offline fallback pages
3. Test in production-like environments
4. Use Cache-Control headers appropriately
5. Monitor cache size to prevent storage quota issues
Conclusion
Modern React provides numerous tools and techniques for building high-performance applications. By understanding
these optimizations, leveraging ecosystem libraries, and monitoring performance metrics, you can build applications that
deliver exceptional user experiences. Remember to profile your specific use cases and optimize where it matters most to
your users.