COMPLETE REACT COURSE  •  PART 3 of 5

Hooks & Real Data

Timers, saving data, talking to servers, touching the DOM and building your own hooks: the tools behind every real React app.

4modules
40practice examples
~17hclass time
100%live code
Keys: → next   ← back   M menu   L Code Lab   F fullscreen
M9
useEffect & Lifecycle
Side effects, dependencies, cleanup
M10
Fetching Data from APIs
fetch, loading/error, POST, TanStack Query
M11
useRef & the DOM
Focus, canvas, timers, previous values
M12
Custom Hooks
useFetch, useLocalStorage, useForm...
BrainBit Infotech, Ranchi  |  Trainer: Nandan Kumar
09
MODULE 9  •  PART 3

useEffect & the Component Lifecycle

Some work happens outside of drawing the screen: timers, saving data, changing the tab title, listening to the keyboard. useEffect is where that code lives.

  • What a "side effect" is
  • Pure rendering (the recipe rule)
  • useEffect syntax
  • The dependency array: 3 cases (animated timeline)
  • Mount, update, unmount
  • Cleanup functions
  • StrictMode and the infinite-loop trap
  • When NOT to use an effect
YOU WILL BUILD:Tab title counterLive clockAuto-save notesExam countdownDebounced searchStopwatch with laps
⏳
App.jsx
useEffect(() => {
  const id = setInterval(tick, 1000);
  return () => clearInterval(id);
}, []);
10examples
● 5 Easy
● 3 Medium
● 2 Hard
each with live code
Complete React Course  |  BrainBit Infotech, Ranchi
M9Real-world use

Where is this used in real apps?

(3) BrainBit Infotech Portal
🕘 10:42:07 AM
clock ticks every second (timer)
💾 Saved 2s ago
notes saved to localStorage
⌨️ Press / to search
keyboard listener
🌐 Loading courses...
API request (Module 10)
The browser tab title says (3) BrainBit Infotech Portal: 3 unread messages

Talking to the outside world

Timers, the browser tab title, localStorage, keyboard and scroll events, network requests: none of these are "drawing JSX".

Effects run AFTER the screen updates

React first paints the UI, then runs your effect. The user never waits for it.

Clean up when you leave

A timer must be stopped when the component disappears, or it keeps running in the background (a "memory leak").
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Core idea

Pure rendering vs side effects

🍳 Rendering should be like a recipe

Same ingredients (props + state) → same dish (JSX), every time. A recipe does not phone your friend or set an alarm. Your component body should only calculate and return JSX.
Wrong.jsx
function Profile({ user }) {
  document.title = user.name;        // side effect in render: BAD
  localStorage.setItem('u', user.id); // BAD
  return <h1>{user.name}</h1>;
}
Side effectExample
TimerssetInterval, setTimeout
Browser APIsdocument.title, localStorage, scroll
Event listenerswindow.addEventListener('keydown')
Networkfetch('/api/students')
Third-party codemaps, charts, video players
Right.jsx
function Profile({ user }) {
  useEffect(() => {
    document.title = user.name;   // GOOD: inside an effect
  }, [user.name]);
  return <h1>{user.name}</h1>;
}
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Live demo

useEffect: your first effect

useEffect(fn, deps) tells React: "after you draw the screen, run fn". Here it updates the browser tab title whenever count changes. Watch the console to see when it runs.
App.jsx
LIVELive Preview
Console
✍ Try it Click twice. The console order is always: render first, effect second.
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Animated explainer

The dependency array: 3 cases

Effect written as...
Render 1
first time (mount)
Render 2
name changed
Render 3
count changed
Render 4
count changed
useEffect(fn)
✓
✓
✓
✓
useEffect(fn, [])
✓
—
—
—
useEffect(fn, [count])
✓
—
✓
✓

No array

Runs after every render. Rarely what you want.

Empty array []

Runs once after the first render. For setup: start a timer, add a listener, load data.

[count]

Runs first time + whenever count changes. List every value from props/state that the effect uses.
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Live demo

The 3 cases live

Three effects in one component. Press the buttons and read the console. Changing name does not trigger the [count] effect.
App.jsx
LIVELive Preview
Console
✍ Try it Click "Change name": only A runs. Click "Change count": A and C run. B never runs again.
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Animated explainer

Lifecycle & cleanup functions

App.jsx
function Clock() {
  const [time, setTime] = useState(new Date());

  useEffect(() => {
    console.log('start timer');
    const id = setInterval(() => setTime(new Date()), 1000);

    return () => {               // cleanup function
      console.log('stop timer');
      clearInterval(id);
    };
  }, []);

  return <h2>{time.toLocaleTimeString()}</h2>;
}
🌱 MOUNTClock appears → effect runs → timer starts
↓
🔄 UPDATE (every second)setTime → re-render. Deps [] unchanged, so the effect does NOT run again
↓
🗑️ UNMOUNTClock is removed (user leaves the page) → React runs the CLEANUP
↓
✅ Timer stoppedno ghost timers, no memory leak
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Live demo

Cleanup live: mount & unmount a timer

Click Show clock to mount it (timer starts), then Hide clock to unmount it (cleanup stops the timer). Without cleanup, hidden clocks would keep ticking forever!
App.jsx
LIVELive Preview
Console
✍ Try it Toggle the clock 3 times and read the console: every start has a matching stop.
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Common mistakes

Two traps: StrictMode & infinite loops

🔁 "My effect runs twice!"

In development, Vite wraps your app in <StrictMode>. React mounts, unmounts and mounts again on purpose to check that your cleanup works. In the production build it runs once. Do not remove StrictMode, fix the cleanup instead.

main.jsx
// main.jsx
createRoot(document.getElementById('root')).render(
  <StrictMode>
    <App />
  </StrictMode>
);

♾ The infinite loop

Wrong.jsx
const [count, setCount] = useState(0);

useEffect(() => {
  setCount(count + 1);   // changes count...
}, [count]);             // ...which re-runs the effect... forever!
Common mistakeAn effect that sets the same state it depends on loops forever and freezes the browser. Ask: does this really need an effect? Often it should be an event handler or a calculated value.
In real projectsInstall the ESLint rule react-hooks/exhaustive-deps (already in Vite templates). It warns you about missing dependencies.
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Best practice

When NOT to use useEffect

SituationDo NOT do thisDo this instead
Value calculated from state/propsuseEffect(() => setTotal(a + b), [a, b])const total = a + b; (derived)
Reacting to a clickset a flag, then react in an effectPut the code directly in the onClick handler
Filtering a listuseEffect(() => setFiltered(...), [list, q])const filtered = list.filter(...)
Resetting state when a prop changeseffect that resets stateGive the component a key so React remounts it
Fetching data in big appsmany hand-written fetch effectsTanStack Query or your framework's data loading (Module 10)
Key ideaOfficial advice from react.dev: "You Might Not Need an Effect". Effects are for syncing with things OUTSIDE React. If no outside system is involved, you probably do not need one.
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Practice 1 of 10  •  Easy

Example 1: Tab Title with Unread Count

● Easy💼 Real project: Gmail, WhatsApp Web, Facebook tabs
When the unread count changes, an effect updates document.title. In a real app look at the browser tab; here we also show the title on screen so you can see it.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Make the title show "🔴" before the count when unread is more than 5.
Inside the effect: (unread > 5 ? '🔴 ' : '') + ...
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Practice 2 of 10  •  Easy

Example 2: Welcome Toast that Hides Itself

● Easy💼 Real project: Notifications, "Saved!" messages
An effect with [] runs once on mount and starts a 3-second setTimeout that hides the toast. The cleanup cancels the timer if the component disappears early.
App.jsxApp.css
LIVELive Preview
Console
✍ Try it yourself Add a close button (×) inside the toast so the user can hide it early.
<button onClick={() => setVisible(false)}>×</button>
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Practice 3 of 10  •  Easy

Example 3: Live Digital Clock

● Easy💼 Real project: Dashboards, attendance kiosks
An interval updates the time every second. It starts on mount and is cleared in the cleanup. Indian date format with toLocaleDateString('en-IN').
App.jsx
LIVELive Preview
Console
✍ Try it yourself Add a line that says "Good morning / afternoon / evening" based on now.getHours().
Reuse the logic from Module 1 Example 6.
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Practice 4 of 10  •  Easy

Example 4: Auto-Save Notes

● Easy💼 Real project: Google Keep, Notion, draft emails
One effect loads the saved note on mount (actually done in the useState initializer). Another effect saves to localStorage whenever the text changes. Refresh with Re-run: your note is still there!
App.jsx
LIVELive Preview
Console
✍ Try it yourself Type a note, then press Re-run on the preview. The note comes back. Add a "Clear note" button.
<button onClick={() => setText('')}>Clear</button> (the effect saves the empty text too).
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Practice 5 of 10  •  Easy

Example 5: Reading Progress Bar

● Easy💼 Real project: Blogs & news articles
We listen to the page scroll event in an effect and calculate how far the reader has scrolled. The listener is removed in the cleanup.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Show a "Back to top ↑" button only when progress is above 30%. Clicking it calls window.scrollTo(0, 0).
{progress > 30 && <button onClick={() => window.scrollTo(0, 0)}>...</button>}
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Practice 6 of 10  •  Medium

Example 6: Exam Countdown Timer

●● Medium💼 Real project: Online tests, OTP timers, sale countdowns
The effect depends on running. When running is true it starts an interval; when paused, the cleanup stops it. At zero we stop automatically and show a message.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Add a progress ring or bar that shrinks as time passes (width = left / START * 100%).
A div with style={{ width: (left / START) * 100 + '%' }} inside a grey track.
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Practice 7 of 10  •  Medium

Example 7: Auto-Play Slider that Pauses on Hover

●● Medium💼 Real project: Homepage banners
The interval effect depends on paused. Hovering sets paused = true, so the cleanup clears the timer; leaving restarts it. Using the updater i => i + 1 avoids stale values.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Add dots under the slider; clicking a dot jumps to that banner.
Map banners to small spans with onClick={() => setI(idx)}.
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Practice 8 of 10  •  Medium

Example 8: Arrow-Key Game Movement

●● Medium💼 Real project: Games, keyboard shortcuts, slideshows
A keydown listener on window moves a character on a grid. We add it in an effect and remove it in the cleanup. Click inside the preview first so it receives your key presses.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Add WASD keys as well as arrow keys.
Add w: [0, -1], s: [0, 1], a: [-1, 0], d: [1, 0] to dirs.
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Practice 9 of 10  •  Hard

Example 9: Debounced Search

●●● Hard💼 Real project: Search boxes that call an API (Amazon, YouTube)
We should not search on every key press. The effect waits 500 ms after the user stops typing; if they type again, the cleanup cancels the old timer. This is called debouncing. Watch the console.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Type "python" quickly: the console shows ONE search, not six. Change the delay to 1000 ms and compare.
Without the cleanup, every key press would trigger a search.
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Practice 10 of 10  •  Hard

Example 10: Stopwatch with Saved Laps

●●● Hard💼 Real project: Sports apps, study timers (Pomodoro)
Combines an interval effect (depends on running), lap recording, and a second effect that persists laps to localStorage. Laps survive a refresh. Fastest and slowest laps are highlighted (derived values).
App.jsxApp.css
LIVELive Preview
Console
✍ Try it yourself Record 3 laps, then press Re-run: they are restored. Add the average lap time below the list.
lapTimes.reduce((a, b) => a + b, 0) / lapTimes.length, formatted with fmt().
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
M9Check your understanding

Quick Quiz

Click an answer. Wrong answers shake, the right one turns green and explains why.

Q1. When does useEffect(fn, []) run?
✔ An empty dependency array means "only on mount".
Q2. What is the cleanup function for?
✔ Return a function from the effect to undo what it started.
Q3. const total = a + b vs an effect that sets total. Which is better?
✔ Derived values do not need effects.
🎯
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 3  |  useEffect & the Component Lifecycle
M9Module summary

Recap: What you learned

  • ✔Effects run AFTER render, for work outside React (timers, title, storage, listeners, network).
  • ✔No array = every render; [] = once; [x] = when x changes.
  • ✔Return a cleanup to stop timers and remove listeners.
  • ✔StrictMode runs effects twice in development to test your cleanup.
  • ✔Never set state that the same effect depends on without a condition.
  • ✔You might not need an effect: derive values, use event handlers.
🏆

Module 9 complete!

Finish all 10 examples and the "Try it yourself" tasks before moving on.

Practice folder: D:\react-practice\m09

➡ Next up

Module 10: Fetching Data from APIs. Load real data with loading and error states.
Complete React Course  |  Part 3  |  useEffect & the Component Lifecycle
10
MODULE 10  •  PART 3

Fetching Data from APIs

Real apps get their data from servers: students from a database, weather from a weather service, products from a shop backend. Learn to load, show and send data safely.

  • What an API and JSON are (waiter analogy)
  • fetch + async/await inside useEffect
  • Loading, error and success states
  • Our classroom mock API
  • Race conditions & AbortController
  • Sending data with POST
  • Skeletons & retry buttons
  • TanStack Query & environment variables
YOU WILL BUILD:Student listWeather appProduct searchFeedback form (POST)Load-more feedCached product list
🌐
App.jsx
useEffect(() => {
  fetch('/api/students')
    .then(res => res.json())
    .then(data => setStudents(data));
}, []);
10examples
● 5 Easy
● 3 Medium
● 2 Hard
each with live code
Complete React Course  |  BrainBit Infotech, Ranchi
M10Real-world use

Where is this used in real apps?

weather.myapp.in
Ranchi
Search
⛅
24°C
Partly cloudy
Behind the scenes
GET /api/weather?city=Ranchi
→ status 200
→ JSON data
skeletons while the forecast loads...

Every app talks to a server

Weather, cricket scores, bank balance, Instagram feed, your school result: all come from APIs as JSON.

3 states to handle

While waiting: show a loader. If it fails: show an error and a retry button. When it works: show the data.

Send data too

Sign-up forms, comments and orders are SENT to the server with a POST request.
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Animated explainer

What is an API? (the restaurant waiter)

🧑‍💻
Your React appthe customer
→
GET /api/students
🧕
APIthe waiter
→
🍳
Server + Databasethe kitchen
response.json (JSON)
[
  { "id": 1, "name": "Aman Kumar", "city": "Ranchi", "marks": 92 },
  { "id": 2, "name": "Priya Singh", "city": "Jamshedpur", "marks": 88 }
]
MethodMeaningExample
GETread dataload students
POSTcreate newsubmit admission form
PUT / PATCHupdateedit profile
DELETEremovedelete a comment
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Practice server

Our classroom mock API (works offline)

RequestReturns
GET /api/students8 students (id, name, class, city, marks)
GET /api/students?city=Ranchifiltered students
GET /api/products ?q=dokra12 Jharkhand handicraft products
GET /api/products/3one product
GET /api/weather?city=Ranchitemp, condition, humidity, wind
GET /api/users/1a user profile
GET /api/posts?page=2&limit=5paged posts: { items, page, totalPages, hasMore }
GET /api/news, /api/tip, /api/quiz, /api/todosheadlines, a random tip, quiz questions, todos
GET /api/errorstatus 500 (to practise errors)
GET /api/slowanswers after 2.5 seconds
POST / PUT any /api/...status 201 with your data + a new id
⏳

Realistic delay

Every request takes about half a second, so you can SEE loading states.
🏠

In your own project

Replace /api/... with a real URL, e.g. your Node/Django backend or a free test API like jsonplaceholder.typicode.com.
🔍

See real requests

In a real app open DevTools (F12) > Network tab to watch every request and response.
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Live demo

fetch inside useEffect

Load data once when the component mounts: useEffect(..., []). fetch() returns a Promise; res.json() turns the response into JavaScript; then we save it in state.
App.jsx
LIVELive Preview
Console
✍ Try it Change the URL to /api/students?city=Ranchi. How many come back?
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Animated explainer

Loading, error, success: the 3 states

⚪ idlenothing requested yet
→
⏳ loadingshow spinner / skeleton
↗
✅ successshow the data
↘
❌ errorshow message + Retry
App.jsx
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

if (loading) return <Spinner />;
if (error) return <p>Error: {error} <button onClick={retry}>Retry</button></p>;
return <StudentTable rows={data} />;
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Live demo

The professional pattern: async/await + states

An effect function cannot be async itself, so we create an async function inside it and call it. res.ok is false for errors like 404/500: we throw so that catch handles it. finally always turns loading off.
App.jsx
LIVELive Preview
Console
✍ Try it Click "User 9": that user does not exist, so you see the error state (HTTP 404).
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Animated explainer

Race conditions & AbortController

time →
type "r"request A sent
type "re"request B sent
B returns firstshows "re" results ✔
A returns LATEoverwrites with "r" results ❌
App.jsx
useEffect(() => {
  const controller = new AbortController();
  fetch('/api/products?q=' + q, { signal: controller.signal })
    .then((r) => r.json()).then(setResults)
    .catch((e) => { if (e.name !== 'AbortError') setError(e.message); });
  return () => controller.abort();   // cancel the old request
}, [q]);
Key ideaWhen q changes, the cleanup aborts the previous request, so a slow old answer can never overwrite the new one.
In real projectsLibraries like TanStack Query handle this for you automatically.
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Live demo

Sending data: POST

To create something on the server, use method: 'POST', a JSON body and a Content-Type header. The server answers with the saved object (here our mock adds an id).
App.jsx
LIVELive Preview
Console
✍ Try it Add a student and check the console: status 201 means "Created".
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Industry tools

TanStack Query & environment variables

⚡ TanStack Query (React Query)

App.jsx
import { useQuery } from '@tanstack/react-query';

function Products() {
  const { data, isPending, error, refetch } = useQuery({
    queryKey: ['products'],
    queryFn: () => fetch('/api/products').then((r) => r.json()),
  });
  if (isPending) return <p>Loading...</p>;
  if (error) return <p>Error!</p>;
  return data.map((p) => <p key={p.id}>{p.name}</p>);
}
Hand-written fetchTanStack Query
3 states by handisPending / error / data given
No cacheCached: instant when you come back
Manual retryAuto retry + refetch on focus
Race bugs possibleHandled for you

🔑 Environment variables

Do not hard-code server URLs or keys. Vite reads a .env file. Only variables starting with VITE_ reach your React code.

.env
# .env  (in the project root)
VITE_API_URL=https://api.brainbit-teaching.com
App.jsx
const API = import.meta.env.VITE_API_URL;
fetch(`${API}/students`);
Common mistakeAnything in the browser can be seen by users. NEVER put secret passwords or private keys in React code or .env files of a front-end app.
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Practice 1 of 10  •  Easy

Example 1: Student List from the API

● Easy💼 Real project: School ERP student register
The simplest data fetch: on mount, GET /api/students, save the array in state, and render a table. Uses async/await inside the effect.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Sort the students by marks (highest first) before rendering.
[...students].sort((a, b) => b.marks - a.marks).map(...)
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Practice 2 of 10  •  Easy

Example 2: Loading Spinner

● Easy💼 Real project: Any screen that waits for data
A loading state starts as true. While loading we show an animated spinner; when the data arrives we turn it off. The /api/slow endpoint takes 2.5 seconds so you can see it clearly.
App.jsxApp.css
LIVELive Preview
Console
✍ Try it yourself Press Re-run to see the spinner again. Then show the number of seconds waited under the spinner.
A second effect with setInterval that counts while loading is true.
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Practice 3 of 10  •  Easy

Example 3: Error Message with Retry

● Easy💼 Real project: Handling "server down" gracefully
We call /api/error, which always fails with status 500. res.ok is false, so we throw, catch it and show a friendly error box. The Retry button increases attempt, which re-runs the effect.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Press Retry until it works (3rd attempt). Then change the condition so it works on the 2nd attempt.
Change attempt < 3 to attempt < 2.
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Practice 4 of 10  •  Easy

Example 4: User Profile by ID

● Easy💼 Real project: Profile pages (/users/42)
The effect depends on userId, so selecting another user fetches again. A small profile card shows the result; a loading flag dims the old card while the new one loads.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Show "Loading..." text next to the select while loading is true.
{loading && <span> Loading...</span>}
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Practice 5 of 10  •  Easy

Example 5: Load News on Button Click

● Easy💼 Real project: Refresh buttons, "tip of the day"
Not every fetch belongs in an effect! When data should load because of a click, call fetch directly in the event handler.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Click "Tip of the day" several times: you get a random tip each time.
Event-driven fetches do not need useEffect at all.
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Practice 6 of 10  •  Medium

Example 6: Weather App by City

●● Medium💼 Real project: Weather apps, travel planners
The user picks a city; on submit we fetch /api/weather?city=.... We handle 404 ("City not found") as an error, and show a weather card on success.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Search "Patna" to see the 404 error. Then add a "Use Celsius / Fahrenheit" toggle (convert on display).
F = C * 9 / 5 + 32. Keep the API data in Celsius; convert only when rendering.
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Practice 7 of 10  •  Medium

Example 7: Product Search with Debounce + Abort

●● Medium💼 Real project: Search-as-you-type on shopping sites
Two professional tricks together: debounce (wait 400 ms after typing) and AbortController (cancel old requests). The cleanup handles both. The console shows which requests are cancelled.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Add a category dropdown (All, Home, Art, Clothing, Jewellery, Handicraft) and send it as &category=.
Add it to the URL only when it is not "All", and add the category state to the dependency array.
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Practice 8 of 10  •  Medium

Example 8: Feedback Form (POST)

●● Medium💼 Real project: Contact forms, reviews, complaints
A controlled form that POSTs JSON to /api/feedback. We disable the button while sending, show the server response, and reset the form. Status 201 = Created.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Log the full response object in the console and point out which fields came from you and which from the server.
name/rating/message are yours; id and savedAt were added by the server.
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Practice 9 of 10  •  Hard

Example 9: Load-More Posts (Pagination)

●●● Hard💼 Real project: Social feeds, blogs, product lists
Each page comes from /api/posts?page=N&limit=5. Clicking Load more fetches the next page and appends it to the list. The API tells us hasMore, so we hide the button at the end.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Turn it into infinite scroll: load the next page automatically when the user scrolls near the bottom.
Add a scroll listener effect (like Module 9 Example 5) that calls setPage when close to the bottom and not loading.
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Practice 10 of 10  •  Hard

Example 10: TanStack Query Product List

●●● Hard💼 Real project: Production apps with caching
The industry-standard way. useQuery gives data, isPending, error and caching. Switch categories and come back: cached data appears instantly (no spinner) while it refreshes in the background.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Click Home, then Art, then Home again: the second time Home appears instantly. Change staleTime to 0 and compare.
With staleTime 0, cached data still shows instantly but it always refetches in the background.
Complete React Course  |  Part 3  |  Fetching Data from APIs
M10Check your understanding

Quick Quiz

Click an answer. Wrong answers shake, the right one turns green and explains why.

Q1. What does res.json() do?
✔ It parses the response body (returns a Promise).
Q2. Why can a fetch result be "out of date" when typing fast?
✔ Abort old requests or ignore their results in the cleanup.
Q3. Which status code means "created" after a POST?
✔ 201 Created. 404 = not found, 500 = server error.
🎯
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 3  |  Fetching Data from APIs
M10Module summary

Recap: What you learned

  • ✔An API returns JSON; GET reads, POST creates, PUT/PATCH update, DELETE removes.
  • ✔Fetch on mount inside useEffect(..., []) with an async inner function.
  • ✔Always handle loading, error (res.ok) and success.
  • ✔Abort or ignore old requests in the cleanup to avoid race conditions.
  • ✔Fetch inside event handlers when data loads because of a click.
  • ✔TanStack Query adds caching and retries; keep URLs in VITE_ env variables.
🏆

Module 10 complete!

Finish all 10 examples and the "Try it yourself" tasks before moving on.

Practice folder: D:\react-practice\m10

➡ Next up

Module 11: useRef & the DOM. Focus inputs, measure elements and remember values without re-rendering.
Complete React Course  |  Part 3  |  Fetching Data from APIs
11
MODULE 11  •  PART 3

useRef & Working with the DOM

Sometimes you need to touch a real DOM element (focus an input, scroll, draw on a canvas) or remember a value without redrawing. That is what refs are for.

  • A ref = a pocket that does not re-render
  • useState vs useRef (animated)
  • Refs to DOM elements
  • Focus, scroll and measure
  • Storing timer ids in refs
  • Remembering the previous value
  • Uncontrolled inputs
  • forwardRef and React 19 ref props
YOU WILL BUILD:Auto-focus searchScroll to sectionSignature padStopwatchOTP inputClick-outside dropdown
📌
App.jsx
const inputRef = useRef(null);

<input ref={inputRef} />
<button onClick={() =>
  inputRef.current.focus()}>
  Search
</button>
10examples
● 5 Easy
● 3 Medium
● 2 Hard
each with live code
Complete React Course  |  BrainBit Infotech, Ranchi
M11Real-world use

Where is this used in real apps?

pay.myapp.in/verify
Enter the OTP sent to 98xxx xx210
4
7
1
|
↑ cursor jumped to box 4 automatically (ref.focus())
✍️ sign here (canvas ref)

Focus management

OTP boxes that move to the next box, search bars that focus on page load, chat inputs that focus after sending.

Direct DOM work

Drawing on a canvas, playing videos, scrolling to a section, measuring an element size.

Remembering without redrawing

Timer ids, previous values, "how many times did this render": values that should not update the screen.
Complete React Course  |  Part 3  |  useRef & Working with the DOM
M11Animated explainer

A ref is a pocket that does not re-render

📦 useState = a notice board

Change it and everyone sees: React re-renders the component.
state value
0
re-render 🔄

👝 useRef = a private pocket

You can put things in and take them out any time, but React does not redraw when it changes.
ref.current (real value) → screen shows
0 → 0
no re-render 😴
useStateuseRef
Returns[value, setValue]{ current: value }
Changing itsetValue(x) → re-renderref.current = x → NO re-render
Use foranything shown on screenDOM elements, timer ids, previous values
Complete React Course  |  Part 3  |  useRef & Working with the DOM
M11Live demo

State vs ref: see the difference

Click "ref + 1" several times: the console shows the ref growing, but the screen does not change. Then click "state + 1": the re-render reveals the ref's real value.
App.jsx
LIVELive Preview
Console
✍ Try it Click "ref + 1" five times, then "state + 1" once. The ref line jumps to 5.
Complete React Course  |  Part 3  |  useRef & Working with the DOM
M11Live demo

Refs to DOM elements

Pass a ref to the ref attribute of any element. After React draws it, ref.current is the real DOM node, so you can call browser methods: focus(), scrollIntoView(), select(), read its size...
App.jsx
LIVELive Preview
Console
✍ Try it Click each button. Then add a button that scrolls the box into view: boxRef.current.scrollIntoView().
Complete React Course  |  Part 3  |  useRef & Working with the DOM
M11Rules

Rules for using refs

✅

Read/write refs in event handlers and effects

That is where the DOM exists and where changing values is safe.
❌

Do not read or write ref.current during render

The JSX would not update when it changes; it makes components unpredictable.
🚪

Refs are an escape hatch

If you can do it with props and state (show/hide, change text, colours), do that instead of touching the DOM.
⚙️

Do not change DOM that React controls

Focus, scroll, measure and play are fine. Do not delete or add elements React manages.
forwardRef.jsx
// React 18: pass a ref to YOUR component with forwardRef
const FancyInput = forwardRef(function FancyInput(props, ref) {
  return <input ref={ref} className="fancy" {...props} />;
});

// React 19: ref is just a normal prop
function FancyInput({ ref, ...props }) {
  return <input ref={ref} className="fancy" {...props} />;
}

// Using it (same in both versions)
const r = useRef(null);
<FancyInput ref={r} />
r.current.focus();
In real projectsOur live previews run React 18, so the examples use forwardRef. In React 19 projects you can skip it.
Complete React Course  |  Part 3  |  useRef & Working with the DOM
M11Practice 1 of 10  •  Easy

Example 1: Auto-Focus the Search Box

● Easy💼 Real project: Google search page, chat apps
When the page loads, an effect calls inputRef.current.focus(), so the user can start typing immediately. (HTML also has an autoFocus attribute, but refs let you focus at ANY time.)
App.jsx
LIVELive Preview
Console
✍ Try it yourself Also select all text when the input is focused: add onFocus={(e) => e.target.select()} and put a default value.
defaultValue="React" and the onFocus handler.
Complete React Course  |  Part 3  |  useRef & Working with the DOM
M11Practice 2 of 10  •  Easy

Example 2: Focus Input on "Edit" Click

● Easy💼 Real project: Inline editing (rename a file, edit a title)
Clicking Edit switches to edit mode with state. After React shows the input, an effect focuses it using the ref. Press Enter to save.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Press Escape to cancel editing and restore the old title.
Save the old title in a ref when editing starts; on Escape, setTitle(oldRef.current) and stop editing.
Complete React Course  |  Part 3  |  useRef & Working with the DOM
M11Practice 3 of 10  •  Easy

Example 3: Scroll to a Section

● Easy💼 Real project: Landing pages with "Contact us" buttons
Each section has its own ref. Clicking a menu button calls scrollIntoView({ behavior: 'smooth' }) on that section.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Add a "Back to top" button in the Contact section.
Add a ref to the nav (or the first section) and scroll to it.
Complete React Course  |  Part 3  |  useRef & Working with the DOM
M11Practice 4 of 10  •  Easy

Example 4: Count Renders with a Ref

● Easy💼 Real project: Debugging performance
A ref survives re-renders but changing it does not cause one, so it is perfect for counting how many times a component rendered (changing state here would loop forever!).
App.jsx
LIVELive Preview
Console
✍ Try it yourself Type 5 letters and check the console count. Why is the number on screen one behind?
The effect increases the ref AFTER the render is shown, and changing the ref does not trigger a new render.
Complete React Course  |  Part 3  |  useRef & Working with the DOM
M11Practice 5 of 10  •  Easy

Example 5: Uncontrolled Form with Refs

● Easy💼 Real project: Simple forms, file inputs, third-party widgets
Instead of state for every field, refs read the values only when the form is submitted. Simpler for small forms, and required for <input type="file">.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Choose an image file and submit. Add a "Reset" button that calls e.target.form.reset().
A <button type="reset"> also works without any code!
Complete React Course  |  Part 3  |  useRef & Working with the DOM
M11Practice 6 of 10  •  Medium

Example 6: Canvas Signature Pad

●● Medium💼 Real project: Delivery apps, digital forms, drawing apps
A canvas needs direct DOM access: the ref gives us the canvas, we get its 2D context and draw lines on mouse moves. A second ref remembers whether the mouse is down (no re-render needed).
App.jsx
LIVELive Preview
Console
✍ Try it yourself Add colour buttons (purple, black, red) that change ctx.strokeStyle.
Get the context from the ref inside the click handler and set strokeStyle.
Complete React Course  |  Part 3  |  useRef & Working with the DOM
M11Practice 7 of 10  •  Medium

Example 7: Stopwatch with an Interval Ref

●● Medium💼 Real project: Timers that start and stop on clicks
The interval id must survive re-renders but should not be shown, so it lives in a ref. Start stores the id; Stop uses it to clear the interval. (Compare with the effect version in Module 9.)
App.jsx
LIVELive Preview
Console
✍ Try it yourself Add a "Resume" button that continues from where it stopped (hint: remember the elapsed time in another ref).
On stop: elapsed.current += now - startTime; on resume start counting again and add elapsed.current to the display.
Complete React Course  |  Part 3  |  useRef & Working with the DOM
M11Practice 8 of 10  •  Medium

Example 8: Price Up / Down Indicator

●● Medium💼 Real project: Stock tickers, live cricket scores, crypto prices
A ref stores the previous price. During each update we compare the new value with prevRef.current to show ▲ or ▼, then save the new value for next time.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Keep a list of the last 10 prices in state and draw tiny bars for them (a mini chart).
setHistory(h => [...h, newPrice].slice(-10)) and map to divs with height based on the price.
Complete React Course  |  Part 3  |  useRef & Working with the DOM
M11Practice 9 of 10  •  Hard

Example 9: OTP Input Boxes with Auto-Advance

●●● Hard💼 Real project: Bank apps, UPI, phone verification
An array of refs points to 6 inputs. Typing a digit focuses the next box; Backspace on an empty box goes back; pasting a 6-digit code fills all boxes. A reusable OtpBox uses forwardRef.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Auto-focus the first box when the component mounts.
useEffect(() => refs.current[0].focus(), [])
Complete React Course  |  Part 3  |  useRef & Working with the DOM
M11Practice 10 of 10  •  Hard

Example 10: Click-Outside to Close Dropdown

●●● Hard💼 Real project: Menus, profile dropdowns, date pickers
A ref on the dropdown container lets us check if a click happened outside it: !ref.current.contains(e.target). The document listener is added only while the menu is open and removed in the cleanup. Escape closes it too.
App.jsx
LIVELive Preview
Console
✍ Try it yourself Put two Dropdowns side by side. Opening one and clicking the other should close the first.
It already works! Each Dropdown has its own ref and listener.
Complete React Course  |  Part 3  |  useRef & Working with the DOM
M11Check your understanding

Quick Quiz

Click an answer. Wrong answers shake, the right one turns green and explains why.

Q1. Changing ref.current causes...
✔ Refs are mutable boxes; React does not watch them.
Q2. Where should you call inputRef.current.focus()?
✔ The DOM element exists only after render; use handlers or effects.
Q3. Best place to keep a setInterval id that must not be displayed?
✔ A ref survives renders without causing them, and each component instance gets its own.
🎯
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 3  |  useRef & Working with the DOM
M11Module summary

Recap: What you learned

  • ✔useRef(initial) returns { current } that survives renders.
  • ✔Changing a ref does NOT re-render; use state for anything on screen.
  • ✔ref={myRef} gives you the real DOM node: focus, scroll, measure, canvas.
  • ✔Store timer ids and previous values in refs.
  • ✔Uncontrolled inputs read values from refs on submit (file inputs need this).
  • ✔forwardRef (React 18) / ref prop (React 19) pass refs to your components.
🏆

Module 11 complete!

Finish all 10 examples and the "Try it yourself" tasks before moving on.

Practice folder: D:\react-practice\m11

➡ Next up

Module 12: Custom Hooks. Package your logic into reusable hooks.
Complete React Course  |  Part 3  |  useRef & Working with the DOM
12
MODULE 12  •  PART 3

Custom Hooks

When the same stateful logic appears in many components, pull it out into your own hook. Custom hooks are how professional React code stays short and clean.

  • Why custom hooks (animated)
  • Anatomy of a custom hook
  • Each component gets its own state
  • Rules for custom hooks
  • Returning values, functions or objects
  • Hooks that use effects
  • Hooks that fetch data
  • Popular hook libraries
YOU WILL BUILD:useToggleuseLocalStorageuseFetchuseDebounceuseFormuseCart
🪝
App.jsx
function useToggle(start = false) {
  const [on, setOn] = useState(start);
  const toggle = () => setOn(o => !o);
  return [on, toggle];
}
10examples
● 5 Easy
● 3 Medium
● 2 Hard
each with live code
Complete React Course  |  BrainBit Infotech, Ranchi
M12Animated explainer

Why custom hooks?

Before: same 8 lines copied 3 times

Navbar
const [w, setW] = useState(...)
useEffect(() => {
  addEventListener('resize'...)
  return () => remove...
}, [])
Sidebar
const [w, setW] = useState(...)
useEffect(() => {
  addEventListener('resize'...)
  return () => remove...
}, [])
Gallery
const [w, setW] = useState(...)
useEffect(() => {
  addEventListener('resize'...)
  return () => remove...
}, [])
Bug in the resize logic? Fix it in 3 places. Forget one = inconsistent app.

After: one custom hook

useWindowWidth.js
// useWindowWidth.js
export function useWindowWidth() {
  const [w, setW] = useState(window.innerWidth);
  useEffect(() => {
    const on = () => setW(window.innerWidth);
    window.addEventListener('resize', on);
    return () => window.removeEventListener('resize', on);
  }, []);
  return w;
}
Navbar
const w = useWindowWidth();
Sidebar
const w = useWindowWidth();
Gallery
const w = useWindowWidth();
Complete React Course  |  Part 3  |  Custom Hooks
M12How it is built

Anatomy of a custom hook

App.jsx
import { useState, useEffect } from 'react';

// 1. Name starts with "use"
// 2. Takes any arguments you want
export function useLocalStorage(key, initialValue) {
  // 3. Uses other hooks inside
  const [value, setValue] = useState(() => {
    const saved = localStorage.getItem(key);
    return saved !== null ? JSON.parse(saved) : initialValue;
  });

  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  // 4. Returns whatever is useful
  return [value, setValue];
}

// In any component:
const [name, setName] = useLocalStorage('name', '');
🏷️

Name starts with use

useSomething. React and ESLint use the name to check the Rules of Hooks.
🧩

Just a function

A custom hook is a normal JavaScript function that calls other hooks. No magic!
📤

Return anything

An array [value, setValue] like useState, an object {{ data, loading }}, or a single value.
📁

Where to keep them

A src/hooks/ folder: useFetch.js, useDebounce.js...
Complete React Course  |  Part 3  |  Custom Hooks
M12Live demo

Each component gets its OWN state

Custom hooks share logic, not state. Two components calling useCounter() each get a separate counter, exactly like calling useState twice.
App.jsxuseCounter.js
LIVELive Preview
Console
✍ Try it Click Post A three times: Post B stays 0. Open the useCounter.js tab to see the hook.
Complete React Course  |  Part 3  |  Custom Hooks
M12Ecosystem

Popular hook libraries (do not reinvent everything)

LibraryGives youExample
@tanstack/react-querydata fetching, caching, mutationsuseQuery, useMutation
react-router-domrouting hooks (Module 14)useNavigate, useParams
react-reduxglobal store hooks (Module 15)useSelector, useDispatch
react-hook-formforms with validationuseForm
usehooks-ts / @uidotdev/usehooksready-made small hooksuseLocalStorage, useDebounce, useOnClickOutside
In real projectsWrite your own hooks to learn and for app-specific logic (useCart, useAuth). For common needs, a well-tested library saves time.
Key ideaHooks can call other hooks. useCart can use useLocalStorage, which uses useState + useEffect. Build big things from small hooks!
Complete React Course  |  Part 3  |  Custom Hooks
M12Practice 1 of 10  •  Easy

Example 1: useToggle

● Easy💼 Real project: Modals, dark mode, show/hide password, menus
The smallest useful hook: a boolean plus a function to flip it. One hook powers three different toggles in the same component.
App.jsxuseToggle.js
LIVELive Preview
Console
✍ Try it yourself Add a third returned value setOn so callers can force it on or off: return [on, toggle, setOn].
Then use const [x, toggleX, setX] = useToggle() and a button onClick={() => setX(false)}.
Complete React Course  |  Part 3  |  Custom Hooks
M12Practice 2 of 10  •  Easy

Example 2: useCounter with Step & Limits

● Easy💼 Real project: Quantity pickers, ratings, sliders
A configurable counter hook: start value, step, min and max. It returns an object so callers pick only what they need.
App.jsxuseCounter.js
LIVELive Preview
Console
✍ Try it yourself Add a third counter for "Guests" from 1 to 6, step 1.
One more useCounter({ start: 1, min: 1, max: 6 }) line and its buttons.
Complete React Course  |  Part 3  |  Custom Hooks
M12Practice 3 of 10  •  Easy

Example 3: useDocumentTitle

● Easy💼 Real project: Every page in a multi-page app
A tiny hook that wraps the effect from Module 9. Pages just call useDocumentTitle('Cart (3)'). The hook also restores the old title when the component unmounts.
App.jsxuseDocumentTitle.js
LIVELive Preview
Console
✍ Try it yourself Watch the console while switching pages and adding items.
The title line under the buttons shows the value from the previous render (the effect runs after render).
Complete React Course  |  Part 3  |  Custom Hooks
M12Practice 4 of 10  •  Easy

Example 4: useLocalStorage

● Easy💼 Real project: Remembering user settings, carts, drafts
Works exactly like useState, but the value is saved in localStorage and comes back after a refresh. Press Re-run after changing things.
App.jsxuseLocalStorage.js
LIVELive Preview
Console
✍ Try it yourself Change all three settings, press Re-run: everything is remembered. Add a "Reset all" button.
Call each setter with its default value.
Complete React Course  |  Part 3  |  Custom Hooks
M12Practice 5 of 10  •  Easy

Example 5: useWindowSize

● Easy💼 Real project: Responsive layouts in JavaScript (mobile vs desktop menus)
The hook listens to resize and returns width and height. The component switches between a mobile and desktop layout. Open it in the Lab and resize the browser window to see it change.
App.jsxuseWindowSize.js
LIVELive Preview
Console
✍ Try it yourself Change the breakpoint from 500 to 700 pixels and see which layout the preview uses.
The preview is about 540 px wide.
Complete React Course  |  Part 3  |  Custom Hooks
M12Practice 6 of 10  •  Medium

Example 6: useFetch Used by Two Components

●● Medium💼 Real project: Any app that loads data in many places
All the loading/error/abort logic from Module 10 lives in useFetch. Now StudentCount and WeatherBadge load data in 1 line each.
App.jsxuseFetch.js
LIVELive Preview
Console
✍ Try it yourself Add a NewsTicker component that uses useFetch('/api/news') and shows the first headline.
Three lines: call the hook, handle loading, show data[0].title.
Complete React Course  |  Part 3  |  Custom Hooks
M12Practice 7 of 10  •  Medium

Example 7: useDebounce for Search

●● Medium💼 Real project: Search boxes, auto-save, resize handlers
useDebounce(value, 500) returns the value only after it stops changing for 500 ms. The input stays instant; the expensive search uses the debounced value.
App.jsxuseDebounce.js
LIVELive Preview
Console
✍ Try it yourself Type "bamboo" quickly and count the API calls in the console. Then use the same hook to debounce a second input.
Hooks are reusable: const d2 = useDebounce(other, 300).
Complete React Course  |  Part 3  |  Custom Hooks
M12Practice 8 of 10  •  Medium

Example 8: useInterval for a Live Score

●● Medium💼 Real project: Live cricket scores, polling dashboards
useInterval(callback, delay) runs the callback every delay ms; pass null to pause. It stores the latest callback in a ref so it never uses stale state.
App.jsxuseInterval.js
LIVELive Preview
Console
✍ Try it yourself Stop the match automatically when wickets reach 10 (pass null as the delay).
useInterval(..., live && wickets < 10 ? 1000 : null)
Complete React Course  |  Part 3  |  Custom Hooks
M12Practice 9 of 10  •  Hard

Example 9: useForm with Validation Rules

●●● Hard💼 Real project: Every form in a real project
A mini version of React Hook Form: give it initial values and validation rules; get back values, errors, handleChange, handleBlur and handleSubmit. The component becomes tiny.
App.jsxuseForm.js
LIVELive Preview
Console
✍ Try it yourself Add a "phone" field with a 10-digit rule. Only App.jsx changes: the hook works for any fields!
Add phone: '' to the initial values, a rule, and {field('phone', 'Mobile')}.
Complete React Course  |  Part 3  |  Custom Hooks
M12Practice 10 of 10  •  Hard

Example 10: useCart with Persistence

●●● Hard💼 Real project: E-commerce apps
All cart logic in one hook: add, remove, change quantity, clear, plus derived count and total. It builds on useLocalStorage (a hook using a hook!), so the cart survives a refresh.
App.jsxuseCart.jsuseLocalStorage.js
LIVELive Preview
Console
✍ Try it yourself Add items, press Re-run: the cart is still there. Add a gst (18%) and grandTotal to what the hook returns.
Compute them from total inside useCart and include them in the returned object.
Complete React Course  |  Part 3  |  Custom Hooks
M12Check your understanding

Quick Quiz

Click an answer. Wrong answers shake, the right one turns green and explains why.

Q1. A custom hook must...
✔ The use prefix lets React check the Rules of Hooks.
Q2. Two components call useCounter(). Do they share the count?
✔ Hooks share logic, not state. Use Context or a store to share state.
Q3. Can a custom hook call another custom hook?
✔ Yes! useCart can use useLocalStorage, which uses useState and useEffect.
🎯
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 3  |  Custom Hooks
M12Module summary

Recap: What you learned

  • ✔Custom hooks extract repeated stateful logic into useSomething().
  • ✔They are normal functions that call other hooks.
  • ✔Each component using a hook gets its own independent state.
  • ✔Return arrays (like useState) or objects (named values).
  • ✔Common hooks: useToggle, useLocalStorage, useFetch, useDebounce, useInterval, useForm.
  • ✔Check libraries before writing complex hooks yourself.
🏆

Module 12 complete!

Finish all 10 examples and the "Try it yourself" tasks before moving on.

Practice folder: D:\react-practice\m12

➡ Next up

Part 4, Module 13: useReducer & Context API. Manage complex and global state.
Complete React Course  |  Part 3  |  Custom Hooks

</> React Code Lab

Console