Level 4 · Full-Stack Application Development · Course 4.2 Frontend Architecture

Module 37: State Management

Goal: decide where each piece of state should live, share state across the app with Context, manage complex changes with reducers, and understand why data from a server is a different kind of state.

You'll need: your multi-page enquiries app from Module 36.

Lessons

  1. 1Local and global state15–25 minutes✓
  2. 2Context15–25 minutes✓
  3. 3Reducers15–25 minutes✓
  4. 4Server state is different15–25 minutes✓
  5. 5Choosing an approach15–25 minutes✓

🛠️Module practice: well-placed state

  1. Sign-in state in an AuthProvider with a useAuth hook.
  2. Enquiries managed by a tested reducer.
  3. Filters in the URL; UI state local.
  4. A "State" section in the README explaining where each piece lives and why. Commit.

✅Module check

Explain in a few sentences, in your own words:

How do you decide where a piece of state should live in a React app?

Show a good answer

A good answer mentions: first, don't store what can be calculated; put shareable view settings in the URL; treat server data as server state managed by a fetching tool; keep UI state local and lift it only to the nearest common parent when shared; use focused Context (with a reducer for complex changes) for app-wide values like the signed-in user; and only bring in a store library for large apps with much shared client state.

📝Module quiz

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

1. Whether a dropdown is open: local or global state?

Why each option is right or wrong

  • “Global, so every component can open or close it” (Incorrect): Other components rarely need this, and global state adds re-renders and complexity.
  • “Global, because all state should live in one place” (Incorrect): One big store for everything makes small changes affect the whole app.
  • “Neither; it should be saved in the database” (Incorrect): It's a momentary UI detail; saving it on the server isn't needed.
  • “Local, in the dropdown component” is correct.

    Only the dropdown cares whether it's open. Keeping that state inside it keeps the component self-contained and means opening it doesn't re-render unrelated parts of the app.

    • Start local: move state up only when another component needs it.
    • Global state: for things many parts of the app share.

📖 Revise: Lesson 1: Local and global state

Question ID module-37-q1 · Report a mistake in this question
2. Who's signed in: local or global state?

Why each option is right or wrong

  • “Local, in the login form component” (Incorrect): Once the form closes, the rest of the app couldn't see who's signed in.
  • “Local, copied into each component that needs it” (Incorrect): Copies drift apart; one shared value is simpler and safer.
  • “Neither; the browser keeps track of it for React” (Incorrect): The browser may store a cookie, but the app still needs the user in state to show it.
  • “Global, because many parts of the app need it” is correct.

    The header shows the person's name, pages check permissions, and API calls may need their token. Since so many places use it, it belongs in shared state such as a context.

    • Typical home: an AuthContext near the top of the app.
    • The server still checks: the frontend value is for display and convenience.

📖 Revise: Lesson 1: Local and global state

Question ID module-37-q2 · Report a mistake in this question
3. What problem does Context solve?

Why each option is right or wrong

  • “Saving state permanently between visits to the site, like a database” (Incorrect): Context lives in memory; it's lost on reload like other state.
  • “Making components render faster than they do with props” (Incorrect): Context can cause extra re-renders; it isn't a speed tool.
  • “Fetching data from the server automatically” (Incorrect): Context only shares values; fetching is separate.
  • “Passing the same props through many components that don't use them” is correct.

    Without context, a value needed deep in the tree must be passed through every component in between, even those that ignore it. This is called prop drilling. Context lets distant components read the value directly.

    • Good uses: current user, theme, language.
    • Not a replacement for all props: most data still flows best as props.

📖 Revise: Lesson 2: Context

Question ID module-37-q3 · Report a mistake in this question
4. Should you put the whole app's state in one context?

Why each option is right or wrong

  • “Yes, one context is simpler and has no downsides” (Incorrect): It causes unnecessary re-renders and tangles unrelated data.
  • “Yes, React allows only one context per app” (Incorrect): You can create as many contexts as you need.
  • “No, because each context can only hold one single value at a time” (Incorrect): A context can hold an object with many values; that's what causes the re-renders.
  • “No, every component using it re-renders on any change; keep contexts focused” is correct.

    Every component that reads a context re-renders when its value changes. With everything in one context, typing in a search box could redraw the header, sidebar and every page. Separate contexts for separate concerns limit this.

    • Example: AuthContext and ThemeContext, not AppContext.
    • Most state: stays local or lifted to the nearest parent.

📖 Revise: Lesson 2: Context

Question ID module-37-q4 · Report a mistake in this question
5. In a reducer, who decides how state changes?

Why each option is right or wrong

  • “Each component changes the state directly as it likes” (Incorrect): With a reducer, components only send actions; they don't change state directly.
  • “The browser decides based on the action's name” (Incorrect): Your reducer function decides; the browser isn't involved.
  • “The server, which receives every action” (Incorrect): useReducer runs in the browser; no server is involved.
  • “The reducer; components only dispatch what happened” is correct.

    Components call dispatch({ type: "closed", id }) to report an event. The reducer function takes the current state and that action, and returns the new state. All the update rules live in one place.

    • Benefit: easy to see every way the state can change.
    • Actions describe events: like added or closed.

📖 Revise: Lesson 3: Reducers

Question ID module-37-q5 · Report a mistake in this question
6. Why is a list of enquiries from the server different from "is the menu open"?

Why each option is right or wrong

  • “It's larger, so it must be stored in a context” (Incorrect): Size isn't the difference; where the data really lives is.
  • “It can't be shown on the screen until the page reloads” (Incorrect): It can be shown as soon as it loads.
  • “It's just as simple; both are ordinary local state” (Incorrect): Server data adds loading, errors and staleness that local UI state doesn't have.
  • “It's a copy of server data that loads, fails and goes stale” is correct.

    The menu's state belongs entirely to the browser. The enquiry list really lives on the server; your app holds a copy that takes time to load, can fail, and may be out of date when someone else changes it.

    • Server state needs: loading and error states, caching and refreshing.
    • Tools: TanStack Query and similar libraries.

📖 Revise: Lesson 4: Server state is different

Question ID module-37-q6 · Report a mistake in this question
7. fullName is stored in state alongside firstName and lastName. What's wrong?

Why each option is right or wrong

  • “Nothing; storing it is faster than joining two strings” (Incorrect): Joining two strings costs almost nothing; the risk is them getting out of sync.
  • “State can hold only two values per component” (Incorrect): Components can hold any number of state values.
  • “fullName must be stored on the server instead” (Incorrect): It can be calculated anywhere; the issue is storing a derived value.
  • “It can be calculated, so it shouldn't be state” is correct.

    If fullName is stored, every change to a first or last name must also update it, and forgetting once makes them disagree. Calculating firstName + " " + lastName while rendering keeps it correct.

    • Rule: don't store what you can derive.
    • Fewer bugs: one source of truth.

📖 Revise: Lesson 5: Choosing an approach

Question ID module-37-q7 · Report a mistake in this question
8. An AI adds Redux to a three-page app with one shared value. What do you ask?

Why each option is right or wrong

  • “Nothing; Redux is required for any React app” (Incorrect): Many React apps work well without Redux.
  • “Ask it to add MobX and Zustand as well, to compare” (Incorrect): Adding more libraries makes the problem bigger, not smaller.
  • “Whether Redux will make the three pages load more quickly for visitors” (Incorrect): Speed isn't the issue; whether the complexity is needed is.
  • “What problem it solves that Context or lifting state wouldn't” is correct.

    Redux is powerful for big apps with lots of shared, changing state, but it adds setup and concepts. For one shared value, lifting state or a small context is simpler. Ask the AI to justify the extra tool.

    • Principle: choose the simplest tool that solves the actual problem.
    • Revisit later: if the app grows, a store may become worthwhile.

📖 Revise: Lesson 5: Choosing an approach

Question ID module-37-q8 · Report a mistake in this question
9. Why is a reducer easy to test?

Why each option is right or wrong

  • “React tests reducers automatically when the app starts” (Incorrect): React doesn't run tests; you write and run them.
  • “Reducers can't contain bugs, so tests always pass” (Incorrect): Reducers can have bugs; being pure just makes them easy to test.
  • “It runs inside a real browser, which makes the test results reliable” (Incorrect): It needs no browser at all, which is part of why it's easy.
  • “It's a pure function: give it state and an action, check the result” is correct.

    A reducer doesn't touch the screen, network or storage. You can call it with a starting state and an action and check the returned state, with no React or browser needed.

    • Example: assert.deepEqual(reducer(start, { type: "closed", id: 1 }), expected).
    • Keep it pure: no fetching or saving inside a reducer.

📖 Revise: Lesson 3: Reducers

Question ID module-37-q9 · Report a mistake in this question
10. What does a tool like TanStack Query take care of?

Why each option is right or wrong

  • “Designing the layout of every page in the app” (Incorrect): It manages server data, not layout.
  • “Storing data permanently without a database” (Incorrect): It caches data in memory; the server still stores it.
  • “Replacing the backend API with browser code” (Incorrect): It talks to your API; it doesn't replace it.
  • “Loading, errors, caching, sharing, refreshing and retrying server data” is correct.

    Writing these by hand for every request is repetitive and error-prone. Query libraries give each request a key, cache the result, share it between components, refetch when it's stale, and retry failures.

    • You still write: the fetch function and what to show.
    • Keys: like ["enquiries", filters] identify each piece of data.

📖 Revise: Lesson 4: Server state is different

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

ProLearners Assist