0% found this document useful (0 votes)
2 views92 pages

ReactJS JavaScript Performance Comprehensive Guide

The document is a comprehensive guide on ReactJS and JavaScript performance optimizations, detailing improvements introduced in various React versions from 16.6 to 19. It covers key features such as lazy loading, hooks, automatic batching, and server components, along with their use cases and performance impacts. Additionally, it discusses ecosystem libraries that enhance performance and developer experience.

Uploaded by

Amar Nath Yogi
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views92 pages

ReactJS JavaScript Performance Comprehensive Guide

The document is a comprehensive guide on ReactJS and JavaScript performance optimizations, detailing improvements introduced in various React versions from 16.6 to 19. It covers key features such as lazy loading, hooks, automatic batching, and server components, along with their use cases and performance impacts. Additionally, it discusses ecosystem libraries that enhance performance and developer experience.

Uploaded by

Amar Nath Yogi
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

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) => ![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.

You might also like