Organise complex state, share it across the app, add multiple pages and make everything fast: the architecture skills companies hire for.
4modules
40practice examples
~19hclass time
100%live code
Keys: → next ← back M menu L Code Lab F fullscreen
M13
useReducer & Context API
Reducers, global data without prop drilling
M14
React Router
Pages, params, layouts, protected routes
M15
Redux Toolkit
Slices, store, thunks, selectors
M16
Performance Optimization
memo, useMemo, useCallback, lazy, virtualization
BrainBit Infotech, Ranchi | Trainer: Nandan Kumar
13
MODULE 13 • PART 4
useReducer & Context API
As apps grow, state gets complicated and must be shared far and wide. useReducer organises complex updates; Context delivers data to any component without prop drilling.
When useState gets messy
Reducers: (state, action) → new state
dispatch, action type & payload (animated)
The prop drilling problem
createContext, Provider, useContext
Context + reducer = a mini global store
Custom hooks for context
Performance & splitting contexts
YOU WILL BUILD:Theme switcherHindi/English toggleAuth login/logoutToast notificationsGlobal cartExpense tracker
🏦
App.jsx
function reducer(state, action) {
switch (action.type) {
case 'deposit':
return state + action.amount;
default: return state;
}
}
● 5 Easy ● 3 Medium ● 2 Hard each with live code
Complete React Course | BrainBit Infotech, Ranchi
M13Motivation
When useState gets messy
Messy.jsx
// 6 setters scattered across many handlers...
function addItem(p) {
setItems([...items, p]);
setCount(count + 1);
setTotal(total + p.price);
setLastAction('add');
setError(null);
setSaved(false);
}
// ...and removeItem, clearCart, applyCoupon all
// repeat similar logic. Easy to forget one!
🧹
useReducer
Puts ALL the update rules in one function called a reducer. Components just say WHAT happened: dispatch({{ type: 'add', item }}).
🔍
Easy to test & debug
Every change goes through one place. You can log each action and see exactly how state changed.
⚖️
Rule of thumb
Use useState for simple independent values. Use useReducer when the next state depends on the previous one in many different ways.
Complete React Course | Part 4 | useReducer & Context API
dispatch(action){ type: 'deposit', amount: 500 } ← the deposit slip
↓
reducer(1000, action)the bank clerk follows the rules
↓
new balance = 1000passbook updated → re-render
Complete React Course | Part 4 | useReducer & Context API
M13Live demo
useReducer live
const [state, dispatch] = useReducer(reducer, initialState). The reducer lives outside the component (it is a pure function). Every action is logged so you can see the flow.
App.jsx
LIVELive Preview
Console
✍ Try it Withdraw until the balance is below 300: the reducer refuses. Add a "Deposit 2000" button.
Complete React Course | Part 4 | useReducer & Context API
M13Animated explainer
Prop drilling vs Context
❌ Prop drilling
<App theme="dark" />
<Layout theme={...} />
<Sidebar theme={...} />
<Menu theme={...} />
<Button />
3 components pass a prop they never use
✅ Context
<ThemeContext.Provider value="dark">
<Layout />
<Sidebar />
<Menu />
<Button />useContext(ThemeContext) → "dark"
Complete React Course | Part 4 | useReducer & Context API
M13Live demo
Context in 3 steps
1.createContext(defaultValue)2. wrap components in <MyContext.Provider value={...}>3. read it anywhere below with useContext(MyContext). When the Provider value changes, every component using it re-renders.
App.jsx
LIVELive Preview
Console
✍ Try it Notice that Toolbar passes no props, yet Button knows the theme. Add a third Button inside Toolbar.
Complete React Course | Part 4 | useReducer & Context API
M13Best practice
Professional pattern: Provider component + custom hook
AuthContext.jsx
// AuthContext.jsx
import { createContext, useContext, useState } from 'react';
const AuthContext = createContext(null);
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const login = (name) => setUser({ name });
const logout = () => setUser(null);
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error('useAuth must be inside <AuthProvider>');
return ctx;
}
Hides the state and functions inside one file. The rest of the app just uses them.
🪝
Custom hook
useAuth() is shorter than useContext(AuthContext) and gives a clear error if you forget the Provider.
Performance tipEvery consumer re-renders when the value changes. Split big contexts (ThemeContext, AuthContext, CartContext) instead of one giant one.
Complete React Course | Part 4 | useReducer & Context API
M13Practice 1 of 10 • Easy
Example 1: Counter with useReducer
● Easy💼 Real project: Learning the reducer pattern
The simplest reducer: actions increment, decrement and reset. The component only dispatches; all logic is in the reducer.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Add an action { type: 'add', amount: 10 } and a "+10" button.
case 'add': return { count: state.count + action.amount };
Complete React Course | Part 4 | useReducer & Context API
M13Practice 2 of 10 • Easy
Example 2: Theme Context for the Whole App
● Easy💼 Real project: Dark mode across every page
A ThemeProvider component owns the theme and a toggle function. A deep Card and the Header read it with a useTheme() hook.
App.jsxThemeContext.jsx
LIVELive Preview
Console
✍ Try it yourself Add a "green" theme palette and make the toggle cycle through all three.
Add green: { bg: '#ebfbee', ... } and cycle with an array of names.
Complete React Course | Part 4 | useReducer & Context API
M13Practice 3 of 10 • Easy
Example 3: English / Hindi Language Switch
● Easy💼 Real project: Multilingual government & school sites
A LanguageContext provides the current language and a translate function t(key). Every component shows text in the chosen language. (Big apps use libraries like react-i18next the same way.)
App.jsxLanguageContext.jsx
LIVELive Preview
Console
✍ Try it yourself Add a new word "contact" in both languages and show it in the Navbar.
English: Contact, Hindi: संपर्क
Complete React Course | Part 4 | useReducer & Context API
M13Practice 4 of 10 • Easy
Example 4: Logged-In User Context
● Easy💼 Real project: Showing the user name in header, sidebar, profile
The user object is provided once at the top. Navbar, Sidebar and ProfileCard all read it directly, without passing it through Layout.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Change the user object in App: all three components update. Add an Avatar component that shows the first letter of the name.
Read the context in Avatar with useContext(UserContext).
Complete React Course | Part 4 | useReducer & Context API
M13Practice 5 of 10 • Easy
Example 5: Form State with a Reducer
● Easy💼 Real project: Large forms with many fields
One SET_FIELD action updates any field using action.field and action.value. A RESET action clears everything. Very handy for forms with 10+ fields.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Add a FILL_DEMO action that fills all fields with sample data (useful for testing).
Complete React Course | Part 4 | useReducer & Context API
M13Practice 7 of 10 • Medium
Example 7: Auth Context: Login / Logout
●● Medium💼 Real project: Every app with user accounts
An AuthProvider exposes user, login and logout. The Navbar and a protected Dashboard react to the login state. A guard in useAuth catches missing Providers.
App.jsxAuthContext.jsx
LIVELive Preview
Console
✍ Try it yourself Save the user in localStorage so a refresh keeps you logged in.
Use the useLocalStorage hook from Module 12 instead of useState inside AuthProvider.
Complete React Course | Part 4 | useReducer & Context API
M13Practice 8 of 10 • Medium
Example 8: Toast Notification System
●● Medium💼 Real project: Success/error popups in every app
Any component can call notify('Saved!', 'success') through context. The ToastProvider keeps a list of toasts and removes each one after 3 seconds.
App.jsxToastContext.jsx
LIVELive Preview
Console
✍ Try it yourself Click the buttons quickly: toasts stack and disappear one by one. Add a "warning" type in orange.
Add warning: '#f08c00' to colors and a button that uses it.
Complete React Course | Part 4 | useReducer & Context API
M13Practice 9 of 10 • Hard
Example 9: Global Cart: Context + useReducer
●●● Hard💼 Real project: E-commerce (Amazon-style cart everywhere)
The classic professional setup: a reducer holds the cart rules, a context shares state and dispatch, and a useCart() hook gives any component access. Header, product list and cart page all stay in sync.
App.jsxCartContext.jsx
LIVELive Preview
Console
✍ Try it yourself Add a "Clear cart" button in CartPanel using the existing CLEAR action.
Complete React Course | Part 4 | useReducer & Context API
M13Practice 10 of 10 • Hard
Example 10: Expense Tracker Store
●●● Hard💼 Real project: Personal finance apps (Walnut, Money Manager)
A full mini app: ExpenseContext + reducer with ADD and DELETE, a form, a list, and a summary with income, expense, balance and a category bar chart, all derived from one transactions array.
App.jsxExpenseContext.jsxApp.css
LIVELive Preview
Console
✍ Try it yourself Add an expense of -300 for "Food" and watch the chart bar grow. Then persist the list in localStorage.
useReducer accepts a 3rd argument (an init function) to load from localStorage; save with an effect.
Complete React Course | Part 4 | useReducer & Context API
M13Check your understanding
Quick Quiz
Click an answer. Wrong answers shake, the right one turns green and explains why.
Q1. A reducer function receives...
✔ reducer(state, action) => newState, and it must not modify the old state.
Q2. What problem does Context solve?
✔ Any component inside the Provider can read the value directly.
Q3. Where can useContext(ThemeContext) read the Provider value?
✔ Outside the Provider you get the default value from createContext.
🎯
Your score: 0 / 3 (first try counts)
Answer all 3 questions. Discuss any wrong answer with your partner before moving on.
Complete React Course | Part 4 | useReducer & Context API
Key ideaReact Router watches the address bar. When it changes, it picks the matching Route and renders its element. The server is not asked for a new page.
In real projectsIn our slides each preview has a fake address bar so you can see the URL change. Click the URL to type your own!
Complete React Course | Part 4 | React Router
M14Live demo
Your first routes (with a fake address bar)
Routes looks at the URL and renders the FIRST matching Route. Link changes the URL without reloading. Try the back/forward buttons in the preview's address bar too.
App.jsx
LIVELive Preview
Console
✍ Try it Add a /gallery page with a Link and a Route. Then type /contact in the fake address bar.
Complete React Course | Part 4 | React Router
M14Important difference
Link vs <a href>
❌ <a href="/about">
The browser asks the server for a brand-new page. The whole app restarts: all state is lost (cart, form, login), and you see a white flash.
App.jsx
<a href="/about">About</a>
VS
✅ <Link to="/about">
React Router changes the URL using the History API and swaps the component. Instant, state is kept, back button still works.
App.jsx
<Link to="/about">About</Link>
🔗
External sites
Use a normal <a href="https://..."> for links to OTHER websites.
🎯
NavLink
Like Link, but knows if it is active: className={{({{ isActive }}) => isActive ? 'on' : ''}}.
🧭
useNavigate
Go to a page from code: after login, after saving a form: navigate('/dashboard').
Complete React Course | Part 4 | React Router
M14Live demo
URL parameters with useParams
A route path like /courses/:id matches /courses/1, /courses/2... Inside the component, useParams() returns { id: '2' } (always a string). One component serves every course page!
App.jsx
LIVELive Preview
Console
✍ Try it Type /courses/3 and then /courses/99 in the address bar.
function RequireAuth({ children }) {
const { user } = useAuth();
if (!user)
return <Navigate to="/login" replace />;
return children;
}
<Route path="/dashboard" element={
<RequireAuth><Dashboard /></RequireAuth>
} />
In real projectsReact Router v7 (2025) also offers data routers (createBrowserRouter with loaders and actions) and a full framework mode. Everything you learn here works in v6 and v7.
Complete React Course | Part 4 | React Router
M14Practice 1 of 10 • Easy
Example 1: Home & About Pages
● Easy💼 Real project: Any multi-page website
The minimum router app: two components, two routes, two links. Use the fake address bar's back button to see browser history working.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Add a Facilities page at /facilities listing Library, Lab and Sports.
New component, new Link, new Route.
Complete React Course | Part 4 | React Router
M14Practice 2 of 10 • Easy
Example 2: NavLink Active Menu
● Easy💼 Real project: Navigation bars that show the current page
NavLink gives isActive to its className or style function, so the current page is highlighted automatically. No state needed!
App.jsxApp.css
LIVELive Preview
Console
✍ Try it yourself Remove the end prop and visit /courses. Why is Home also active now?
Without end, "/" matches the start of every URL. end means "match exactly".
Complete React Course | Part 4 | React Router
M14Practice 3 of 10 • Easy
Example 3: 404 Not Found Page
● Easy💼 Real project: Every production website
A route with path="*" catches every URL that did not match. Always put it last. A good 404 page links back home.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Type any random URL like /abc/xyz in the address bar.
Anything that does not match shows NotFound.
Complete React Course | Part 4 | React Router
M14Practice 4 of 10 • Easy
Example 4: Course Detail Page (/courses/:id)
● Easy💼 Real project: Product, blog post and profile pages
The list links to /courses/react, /courses/python... One CourseDetail component reads the :slug parameter and finds the right course.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Add a "Next course →" link at the bottom of the detail page.
Find the index of the current course and link to courses[(i + 1) % courses.length].slug.
Complete React Course | Part 4 | React Router
M14Practice 5 of 10 • Easy
Example 5: Redirect after Form Submit
● Easy💼 Real project: Sign-up and checkout flows
After submitting, call navigate('/thank-you', { state: { name } }). The thank-you page reads that data with useLocation().state.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Use navigate('/thank-you', { replace: true, state }) so the Back button does not return to the form.
replace swaps the current history entry instead of adding a new one.
Complete React Course | Part 4 | React Router
M14Practice 6 of 10 • Medium
Example 6: Dashboard with Nested Routes
●● Medium💼 Real project: Admin panels, student portals
A parent route renders DashboardLayout (sidebar + <Outlet />). Child routes fill the outlet. The index route is the default child.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Add a "Certificates" child route at /dashboard/certificates.
A new NavLink in the sidebar and a new child Route inside the dashboard route.
Complete React Course | Part 4 | React Router
M14Practice 7 of 10 • Medium
Example 7: Filters in the URL (useSearchParams)
●● Medium💼 Real project: Shopping filters you can bookmark and share
The category and sort live in the URL query string (?category=Art&sort=price) instead of state. Copy the URL, open it later, and the same filters appear.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Click filters and watch the address bar. Then type /?category=Home&sort=price directly.
The page reads everything from the URL, so typing it gives the same result.
Complete React Course | Part 4 | React Router
M14Practice 8 of 10 • Medium
Example 8: Breadcrumbs from the URL
●● Medium💼 Real project: E-commerce and documentation sites
useLocation() gives the current path. We split it into parts and build clickable breadcrumbs: Home › Shop › Art › Sohrai.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Navigate to "Sohrai Painting", then click "Art" in the breadcrumbs.
Every crumb is a Link built from the path pieces before it.
Complete React Course | Part 4 | React Router
M14Practice 9 of 10 • Hard
Example 9: Protected Dashboard (Login Required)
●●● Hard💼 Real project: Banking, school portals, admin areas
A RequireAuth wrapper checks the auth context. Not logged in? It redirects to /login with <Navigate /> and remembers where you wanted to go, then sends you back after login.
App.jsx
LIVELive Preview
Console
✍ Try it yourself As a guest, click Reports: you go to login, then back to Reports after logging in. Add an admin-only page.
Store a role in the user and make a RequireAdmin wrapper that checks user.role === 'admin'.
Everything together: routes for home, product details (:id), cart and order success; a cart context shared across pages; useNavigate after checkout; a cart badge in the header.
App.jsxpages.jsxcart.jsx
LIVELive Preview
Console
✍ Try it yourself Add a /checkout page with a name/address form between Cart and Success.
Cart button navigates to /checkout; the checkout form submit clears the cart and navigates to /success.
Complete React Course | Part 4 | React Router
M14Check your understanding
Quick Quiz
Click an answer. Wrong answers shake, the right one turns green and explains why.
Q1. Why use <Link> instead of <a href> inside your app?
✔ Link uses client-side navigation: instant and state is preserved.
Q2. For the route /student/:roll, how do you read the roll number?
✔ useParams returns all URL parameters as strings.
Q3. In nested routes, where does the child page appear?
✔ Outlet is the placeholder for the matched child route.
🎯
Your score: 0 / 3 (first try counts)
Answer all 3 questions. Discuss any wrong answer with your partner before moving on.
Complete React Course | Part 4 | React Router
M14Module summary
Recap: What you learned
✔Wrap the app in <BrowserRouter>; define <Routes> and <Route path element>.
✔Use Link/NavLink for internal navigation, never <a>.
✔useNavigate() to move from code; <Navigate /> to redirect.
✔path="*" for 404; wrapper components for protected routes.
🏆
Module 14 complete!
Finish all 10 examples and the "Try it yourself" tasks before moving on.
Practice folder: D:\react-practice\m14
➡ Next up
Module 15: Redux Toolkit. Professional global state for large apps.
Complete React Course | Part 4 | React Router
15
MODULE 15 • PART 4
Redux Toolkit (Global State)
Big apps (e-commerce, ERPs, dashboards) keep shared data in one central store. Redux Toolkit is the official, modern way to do that, and it is asked about in many React job interviews.
Why a global store?
The Redux flow (animated)
Slices: state + reducers + actions
configureStore and Provider
useSelector and useDispatch
Async data with createAsyncThunk
Selectors & createSelector
Redux vs Context vs Zustand
YOU WILL BUILD:Counter & theme slicesTodo sliceCart with totalsAsync product loadingAuth + cart storeAttendance stats app
// 2. store.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './features/counterSlice';
export const store = configureStore({
reducer: { counter: counterReducer },
});
main.jsx
// 3. main.jsx: give the store to the whole app
import { Provider } from 'react-redux';
import { store } from './store';
<Provider store={store}>
<App />
</Provider>
Counter.jsx
// 4. Any component
import { useSelector, useDispatch } from 'react-redux';
import { increment, addBy } from './features/counterSlice';
const value = useSelector((state) => state.counter.value);
const dispatch = useDispatch();
<button onClick={() => dispatch(addBy(5))}>+5</button>
Key ideastate.value += 1 looks like mutation, but Redux Toolkit uses a library called Immer that turns it into a safe, immutable update. This only works inside createSlice reducers!
Everything in one file for the demo (in real projects split it as on the previous slide). Two different components read and change the SAME store. Actions are logged with their auto-generated type.
App.jsx
LIVELive Preview
Console
✍ Try it Check the console: addBy(5) creates { type: "counter/addBy", payload: 5 }. Add a decrement reducer and button.
Large apps, many features, team projects, DevTools time-travel
E-commerce cart + orders + user + products
Zustand
Simple global store with very little code
Small-medium apps, game state
TanStack Query / RTK Query
Server data (cache of API responses)
Product lists, user profiles
zustand-example.js
// Zustand: a whole store in 6 lines
import { create } from 'zustand';
const useCart = create((set) => ({
items: [],
add: (p) => set((s) => ({ items: [...s.items, p] })),
}));
const items = useCart((s) => s.items);
Key ideaDo not put EVERYTHING in Redux. Form inputs and UI toggles usually stay local. Server data is best in a query library. Redux is for shared client state.
● Easy💼 Real project: Dashboards: counts, totals, percentages
Selectors are small functions that read or calculate from the store: selectDoneCount, selectProgress. Keep them next to the slice and reuse them everywhere.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Add a selectNextLesson selector that returns the first lesson not done, and show "Next: ..." under the bar.
(s) => s.lessons.find(l => !l.done)?.title || 'All done!'
●● Medium💼 Real project: Real store shape with many features
A real store has many slices: auth and cart here. A component can select from both. Notice how logging out also clears the cart: the cart slice listens to the auth logout action using extraReducers.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Log in, add 3 items, log out: the cart empties. Log the whole store state with store.getState() in the console.
store.subscribe(() => console.log(store.getState())) logs after every action.
Filters live in a filters slice; products in a products slice. createSelector builds a memoized selector: the filtered list is only recalculated when products or filters change (the console shows when).
App.jsx
LIVELive Preview
Console
✍ Try it yourself Click "Toggle theme": the console does NOT show "recalculating" because the inputs to the selector did not change. Move the slider: it does.
createSelector caches the last result and returns it when its input selectors return the same values.
●●● Hard💼 Real project: School ERP attendance module
A students slice with markPresent, markAbsent and markAll. Selectors compute present/absent counts and percentage; an SVG donut chart and bar show the stats live.
App.jsxattendanceSlice.jsstore.jsDonut.jsx
LIVELive Preview
Console
✍ Try it yourself Add a "Late" status (L, orange) to the buttons, the selector and the donut.
Add 'L' to the button list, count it in selectStats, and add a third coloured segment.
wrap Footer & ProductList in memo()skip render when props are the same
1
State changes
The component with the state re-renders.
2
Children follow
By default ALL its children re-render too, even if their props did not change.
3
Usually fine!
Re-rendering is cheap; React only touches the DOM if output changed. Optimise only when something is actually slow.
Complete React Course | Part 4 | Performance Optimization
M16Live demo
See re-renders happen (render badges)
Each component shows how many times it has rendered; the badge flashes on every render. Type in the box: Parent, Child AND Footer all re-render, even though Footer receives no props at all.
App.jsxRenderCount.jsx
LIVELive Preview
Console
✍ Try it Type 5 letters and watch all badges grow. Next slide: stop Footer from re-rendering.
Complete React Course | Part 4 | Performance Optimization
M16The 3 tools
React.memo, useMemo, useCallback
🛡️ React.memo(Component)
Skip re-rendering a component if its props are the same as last time (shallow compare).
Common mistakeThe trap:memo compares props with ===. A new object {{}}, array [] or arrow function () => {{}} created during render is a NEW reference every time, so memo always re-renders. Fix it with useMemo / useCallback.
In real projectsReact Compiler (stable since late 2025) can add this memoization automatically at build time. Learn the concepts anyway: you need them to understand and debug React apps.
Complete React Course | Part 4 | Performance Optimization
M16Animated explainer
Code splitting: lazy() + Suspense
Without code splitting
app.js 2.4 MB (Home + Admin + Charts + Editor)
⏳ The user waits for EVERYTHING, even pages they never open.
With lazy() + Suspense
main.js 300 KB (Home) ✅ loaded first
Charts.js 600 KB: loaded when the user opens Reports
// useDeferredValue: show the input instantly,
// let the slow list catch up a moment later
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
<input value={query} onChange={(e) => setQuery(e.target.value)} />
<SlowList query={deferredQuery} />
useTransition
// useTransition: mark an update as "not urgent"
const [isPending, startTransition] = useTransition();
function selectTab(tab) {
startTransition(() => setTab(tab)); // can be interrupted
}
{isPending && <Spinner />}
⌨️
Urgent updates
Typing, clicking, pressing: the user expects instant feedback.
🐴
Non-urgent updates
Filtering a huge list, switching to a heavy tab: a small delay is OK.
🧠
Concurrent React
React 18+ can pause a slow render to handle typing first, then continue. These two hooks tell React what can wait.
📊
Measure first!
Open React DevTools > Profiler, record, and look for components that take many milliseconds. Fix those, not everything.
Complete React Course | Part 4 | Performance Optimization
M16Practice 1 of 10 • Easy
Example 1: Render Counter: Who Re-rendered?
● Easy💼 Real project: Debugging performance problems
Three cards show their render counts. Clicking "Like" on one card re-renders the parent, so ALL cards re-render. This is the baseline we will optimise in the next example.
App.jsxRenderCount.jsx
LIVELive Preview
Console
✍ Try it yourself Like "React" 3 times. How many times did Python and Java render? (They did not need to!)
Each click re-renders App, and App re-renders every child.
Complete React Course | Part 4 | Performance Optimization
M16Practice 2 of 10 • Easy
Example 2: React.memo Stops Extra Renders
● Easy💼 Real project: Lists of cards, table rows, sidebars
Wrapping Footer and Sidebar in memo() makes them skip re-rendering when their props are unchanged. Type in the box: only Parent and Preview re-render now.
App.jsxRenderCount.jsx
LIVELive Preview
Console
✍ Try it yourself Change links="Home, Courses" to links={["Home", "Courses"].join(", ")}. Still memoized? Now try links={["Home"]} (an array). What happens and why?
A string is compared by value, but a new array is a new reference each render, so memo cannot skip.
Complete React Course | Part 4 | Performance Optimization
M16Practice 3 of 10 • Easy
Example 3: useMemo for a Filtered List
● Easy💼 Real project: Search over big datasets
Filtering 5,000 students on every render wastes time when only the theme changes. useMemo remembers the result and re-filters only when query changes. Watch the console timing.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Toggle the theme: no "filtered in" log. Remove useMemo (plain calculation) and toggle again: now it filters every time.
Replace useMemo(() => ..., [query]) with a direct calculation and compare the console.
Complete React Course | Part 4 | Performance Optimization
M16Practice 4 of 10 • Easy
Example 4: useCallback + memo Child
● Easy💼 Real project: Passing handlers to optimised children
AddButton is memoized, but the parent creates a NEW onAdd function every render, so memo is useless. useCallback keeps the same function, and the child finally skips renders.
App.jsxRenderCount.jsx
LIVELive Preview
Console
✍ Try it yourself Type in the input and compare the two badges.
Only the button without useCallback re-renders while typing.
Complete React Course | Part 4 | Performance Optimization
M16Practice 5 of 10 • Easy
Example 5: Lazy-Loaded Chart with Suspense
● Easy💼 Real project: Reports pages, admin dashboards
lazy() loads HeavyChart only when the user clicks "Show report". Suspense shows a fallback while it loads. We add a fake 1.2 s delay to simulate a slow network.
App.jsxHeavyChart.jsx
LIVELive Preview
Console
✍ Try it yourself Press Re-run, then click "Show report". The console log appears only after you click.
In a real Vite build, HeavyChart.jsx becomes its own .js file downloaded on demand.
Complete React Course | Part 4 | Performance Optimization
M16Practice 6 of 10 • Medium
Example 6: 2,000-Row Search with useDeferredValue
●● Medium💼 Real project: Big tables and search results
The list is slow on purpose (each row does extra work). With useDeferredValue, the input stays smooth: React shows your typing first and updates the list when it has time. The faded list means "updating".
App.jsx
LIVELive Preview
Console
✍ Try it yourself Type fast. Then replace query={deferred} with query={query} and type again: notice the input lag.
Without deferring, every key press waits for the slow list to render.
Complete React Course | Part 4 | Performance Optimization
M16Practice 7 of 10 • Medium
Example 7: useTransition for a Slow Tab
●● Medium💼 Real project: Dashboards with heavy tabs
The "Posts" tab renders slowly. Wrapping the tab change in startTransition keeps buttons responsive: you can click another tab while Posts is still rendering, and isPending shows a hint.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Click "posts" then immediately "contact": the app switches to contact without waiting. Try again without startTransition (call setTab directly).
Without a transition the UI freezes until Posts finishes rendering.
Complete React Course | Part 4 | Performance Optimization
M16Practice 8 of 10 • Medium
Example 8: Prime Calculator: Measure with and without useMemo
●● Medium💼 Real project: Heavy maths in apps (reports, games)
Counting primes up to N is slow. We time it with performance.now(). With useMemo, clicking the unrelated counter costs ~0 ms; without it, every click recalculates.
App.jsx
LIVELive Preview
Console
✍ Try it yourself With useMemo ON, click "Unrelated click" and read the time. Turn it OFF and click again.
Only changing N should trigger the expensive calculation.
Complete React Course | Part 4 | Performance Optimization
M16Practice 9 of 10 • Hard
Example 9: Virtualized 10,000-Row List
●●● Hard💼 Real project: Huge tables: logs, chats, stock data
Rendering 10,000 rows creates 10,000 DOM nodes. Virtualization renders only the ~15 rows you can SEE, positioned inside a tall scroll area. Libraries: react-window, TanStack Virtual. Here is how they work inside.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Scroll fast to the bottom: still smooth! Open DevTools Elements in the Lab version and count the row divs.
Only about 15-20 row elements exist at any moment.
Complete React Course | Part 4 | Performance Optimization
M16Practice 10 of 10 • Hard
Example 10: Optimise a Dashboard (Render Chart)
●●● Hard💼 Real project: Real-world performance tuning
A dashboard with a clock ticking every second. Toggle Optimised to switch between plain components and memo + useMemo + useCallback versions. The bar chart shows total renders of each widget: watch the difference!
App.jsx
LIVELive Preview
Console
✍ Try it yourself Watch for 10 seconds unoptimised, then tick "Optimised": Stats and List stop growing while the clock keeps ticking.
Stable props (useMemo/useCallback) + memo children = they skip every clock tick.
Complete React Course | Part 4 | Performance Optimization
M16Check your understanding
Quick Quiz
Click an answer. Wrong answers shake, the right one turns green and explains why.
Q1. What does React.memo(Comp) do?
✔ It shallow-compares props and reuses the last render if they are equal.
Q2. Why might a memo child still re-render every time?
✔ New references fail the === check. Stabilise them with useMemo/useCallback.
Q3. What is the FIRST step in performance work?
✔ Optimise what you measured; premature optimisation adds complexity.
🎯
Your score: 0 / 3 (first try counts)
Answer all 3 questions. Discuss any wrong answer with your partner before moving on.
Complete React Course | Part 4 | Performance Optimization
M16Module summary
Recap: What you learned
✔State change → component + all children re-render (usually fine).
✔Measure with React DevTools Profiler before optimising.
✔memo skips renders when props are equal; useMemo caches values; useCallback caches functions.
✔lazy() + <Suspense> split code so pages load faster.
✔useDeferredValue / useTransition keep typing and clicks smooth.
✔Virtualize huge lists: render only visible rows.
🏆
Module 16 complete!
Finish all 10 examples and the "Try it yourself" tasks before moving on.
Practice folder: D:\react-practice\m16
➡ Next up
Part 5, Module 17: Advanced Patterns. Portals, error boundaries, compound components and React 19.
Complete React Course | Part 4 | Performance Optimization