Level 4 · Full-Stack Application Development · Course 4.1 React Fundamentals

Module 34: React Hooks

Goal: use useEffect to connect components to the world outside React, useRef to hold values and reach elements, write your own hooks, and avoid the most common hook mistakes.

You'll need: your enquiries project from Module 33.

Lessons

  1. 1Effects with useEffect15–25 minutes✓
  2. 2Dependencies and cleanup15–25 minutes✓
  3. 3useRef15–25 minutes✓
  4. 4Custom hooks15–25 minutes✓
  5. 5The rules of hooks and common mistakes15–25 minutes✓

🛠️Module practice: a dashboard that remembers

  1. Enquiries saved and loaded with a useLocalStorage hook.
  2. A debounced search using a useDebounce hook.
  3. Keyboard shortcut / to focus search, with proper listener cleanup.
  4. "Last updated" time refreshing each minute with cleanup.
  5. A comment on every effect naming the outside system it connects to. No hook lint warnings. Commit.

✅Module check

Explain in a few sentences, in your own words:

What is useEffect for, when is it not needed, and what are the rules of hooks?

Show a good answer

A good answer mentions: useEffect runs code after rendering to sync with things outside React (localStorage, timers, listeners, the page title, fetching), re-running when its dependencies change, and returning a cleanup function to undo itself. It isn't needed for values that can be calculated during rendering. useRef holds values or element references without re-rendering. Hooks must be called at the top level of components or custom hooks, in the same order every render; custom hooks (named use…) share stateful logic.

📝Module quiz

10 questions · 10 marks each · 100 marks in all · pass mark 70% · retry as often as you like ·

1. Why not fetch data directly in the component's body?

Why each option is right or wrong

  • “Fetching in the body is fine, but it's slower than an effect” (Incorrect): Speed isn't the issue; it runs on every render and can loop.
  • “Components can't use fetch; only the backend can” (Incorrect): Components can fetch, inside an effect or an event handler.
  • “The data would be shown to the user before it's checked” (Incorrect): The real problem is repeated fetches on every render.
  • “Rendering should only calculate what to show; outside work belongs in an effect” is correct.

    React may render a component many times. A fetch in the body would run on every render, and setting state with the result triggers another render, and another fetch, in a loop. useEffect runs after rendering and only when its dependencies change.

    • Effects are for: fetching, timers, subscriptions, saving to storage.
    • Larger apps: data libraries like TanStack Query handle fetching for you.

📖 Revise: Lesson 1: Effects with useEffect

Question ID module-34-q1 · Report a mistake in this question
2. You calculate filtered in an effect and store it in state. What's simpler?

Why each option is right or wrong

  • “Use two effects, one to filter and one to sort” (Incorrect): More effects add more renders and more chances to get out of step.
  • “Store it in local storage and read it back each time” (Incorrect): That's slower and more complex for a value you can just calculate.
  • “Move the calculation to the server, even for small lists” (Incorrect): A filter over a small list is easily done during rendering.
  • “Calculate it directly during rendering” is correct.

    If a value can be worked out from props or state, calculate it as you render: const filtered = items.filter(...). An effect plus extra state adds an extra render and a chance for the two to be out of step.

    • Very slow calculation? useMemo can cache it.
    • Effects are for: the outside world, not deriving values.

📖 Revise: Lesson 1: Effects with useEffect

Question ID module-34-q2 · Report a mistake in this question
3. An effect uses query but its dependency list is []. What goes wrong?

Why each option is right or wrong

  • “It runs again on every single render, which slows the whole page down” (Incorrect): That happens with no dependency list at all. [] runs it only once.
  • “React shows an error and refuses to run the effect” (Incorrect): React runs it; the lint rule may warn, but there's no error.
  • “It runs twice as often as it should when query changes” (Incorrect): With [] it doesn't run again when query changes.
  • “It keeps using the first value of query and doesn't see updates” is correct.

    [] tells React to run the effect only once, after the first render. When query changes, the effect doesn't run again, so it searches with stale data. Listing query in the dependencies makes it rerun.

    • Rule: list every value from the component the effect uses.
    • Lint rule: react-hooks/exhaustive-deps warns about missing ones.

📖 Revise: Lesson 2: Dependencies and cleanup

Question ID module-34-q3 · Report a mistake in this question
4. Why does an interval started in an effect need cleanup?

Why each option is right or wrong

  • “Intervals only start working after a cleanup function is added” (Incorrect): The interval runs either way. Cleanup is about stopping it.
  • “Cleanup makes the interval tick more accurately” (Incorrect): Cleanup stops the interval; it doesn't change its timing.
  • “Browsers block any interval that runs longer than a minute” (Incorrect): Intervals can run for as long as the page is open, which is why cleanup matters.
  • “Otherwise it keeps running after the component is gone, and intervals stack up” is correct.

    An interval doesn't stop by itself. If the effect runs again, or the component is removed, a new interval starts while the old one carries on. Returning () => clearInterval(id) from the effect stops it at the right time.

    • Same for: event listeners, subscriptions and connections.
    • In development: React runs effects twice to help you spot missing cleanup.

📖 Revise: Lesson 2: Dependencies and cleanup

Question ID module-34-q4 · Report a mistake in this question
5. What's the difference between changing a ref and changing state?

Why each option is right or wrong

  • “Refs are saved permanently; state is lost when the page closes” (Incorrect): Both are lost when the page closes.
  • “State holds numbers; refs can only hold page elements” (Incorrect): Refs can hold any value, including numbers and timer ids.
  • “There's no difference; refs are an older name for state” (Incorrect): They behave differently: only state changes trigger a re-render.
  • “Changing state re-renders; changing a ref doesn't” is correct.

    Both keep a value between renders. Setting state tells React to redraw. Changing ref.current just stores the new value quietly, which suits values the screen doesn't depend on, like a timer id.

    • Show it on screen? Use state.
    • Just remember it? A ref is fine.

📖 Revise: Lesson 3: useRef

Question ID module-34-q5 · Report a mistake in this question
6. Which is a good use for a ref?

Why each option is right or wrong

  • “Storing the list of enquiries shown on the screen” (Incorrect): Data the screen shows needs state, so changes are drawn.
  • “Holding the text of an input that's shown as you type” (Incorrect): Text shown as you type should be state, for a controlled input.
  • “Passing data from a parent component to its child” (Incorrect): That's what props are for.
  • “Focusing an input” is correct.

    To focus a field, you need the actual element on the page. ref={inputRef} gives you that element in inputRef.current, so you can call inputRef.current.focus().

    • Other uses: storing a timer id or measuring an element's size.
    • Not for: values shown on screen, which need state.

📖 Revise: Lesson 3: useRef

Question ID module-34-q6 · Report a mistake in this question
7. Why can't you call useState inside an if?

Why each option is right or wrong

  • “if statements aren't allowed anywhere in React components” (Incorrect): Components can use if freely; just not around hook calls.
  • “React would lose track of which component the state belongs to” (Incorrect): React knows the component; within it, the order of hook calls is what would break.
  • “Hooks only work inside loops, not conditions” (Incorrect): Hooks shouldn't be in loops either; they belong at the top level.
  • “React tracks hooks by call order, which a condition would change” is correct.

    React doesn't know hooks by name. It remembers them by their order: first hook, second hook and so on. If a hook is skipped on one render, every later hook gets the wrong stored value.

    • Rule: call hooks at the top level of the component, every time.
    • Condition inside instead: put the if inside the effect, not around the hook.

📖 Revise: Lesson 5: The rules of hooks and common mistakes

Question ID module-34-q7 · Report a mistake in this question
8. The console shows "Maximum update depth exceeded". What's a likely cause?

Why each option is right or wrong

  • “The component has more than a hundred lines of code” (Incorrect): Length doesn't cause this error; a state update loop does.
  • “Too many components are open in the browser tab at the same time” (Incorrect): This is a loop inside one component, not a limit on components.
  • “The computer's memory is full and needs a restart” (Incorrect): A restart won't help; the code is updating state in a loop.
  • “Setting state in render or an effect that triggers itself in a loop” is correct.

    Each state change causes a render. If the render, or an effect it triggers, sets state again unconditionally, React re-renders again and again until it stops with this error.

    • Common causes: onClick={setOpen(true)}, or an effect that sets a value listed in its own dependencies.
    • Fix: set state only in response to something, like an event or a real change.

📖 Revise: Lesson 5: The rules of hooks and common mistakes

Question ID module-34-q8 · Report a mistake in this question
9. Two components use useLocalStorage with different keys. Do they share state?

Why each option is right or wrong

  • “Yes, all calls to a custom hook share one state” (Incorrect): Each call creates its own state.
  • “Yes, because local storage is the same for the whole site” (Incorrect): The storage is shared, but different keys keep the values separate.
  • “Only if both components are on the same page at once” (Incorrect): Even then, each call has its own state.
  • “No, each call has its own state; only the logic is shared” is correct.

    A custom hook is a reusable recipe. Every component that calls it gets its own state, just as calling useState twice gives two separate values. Here they also use different storage keys.

    • Sharing data between components: lift state up or use context.
    • Custom hooks share how, not what.

📖 Revise: Lesson 4: Custom hooks

Question ID module-34-q9 · Report a mistake in this question
10. Why must a custom hook's name start with use?

Why each option is right or wrong

  • “Functions without the use prefix can't return any values to components” (Incorrect): Any function can return values; the prefix is about hook rules.
  • “It makes the hook run faster than normal functions” (Incorrect): The name doesn't affect speed.
  • “Browsers only load JavaScript functions that start with use” (Incorrect): Browsers load any function; the prefix matters to React's tools.
  • “So React and its lint rules check the rules of hooks inside it” is correct.

    The use prefix tells React's tools that the function calls hooks, so they apply the rules: top level only, not inside conditions. Without it, mistakes inside the hook could go unflagged.

    • Readers benefit too: useSomething signals it holds state or effects.
    • Plain helper? If it calls no hooks, it doesn't need the prefix.

📖 Revise: Lesson 4: Custom hooks

Question ID module-34-q10 · Report a mistake in this question

ProLearners Assist