Chapters

Hide chapters

React Apprentice

First Edition · web · React 19 · Visual Studio Code

Section I: Rendering Right

Section 1: 7 chapters
Show chapters Hide chapters

11. Designing State & Building My Learning
Written by Eli Ganim

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

In the previous chapter, you mastered how state updates. This chapter tackles the other half of the craft: where state should live. It’s the question behind the crack you’ve been stepping over since Chapter 8 — cards that know their favorite status while the header, the banner and every other component stay ignorant.

The fix is one of React’s fundamental moves: lifting state up to the closest component that all interested parties share, then passing data down and actions up. You’ll rebuild favorites that way, and the whole page will finally agree on what’s favorited.

Then comes the payoff feature, the one the app is named for: My Learning — a plan that tracks courses from planned through in progress to completed. Its state has enough moving parts to earn your first reducer, React’s tool for state whose updates deserve a dedicated, testable home.

The Trouble With Private State

Diagnose before operating. Each CourseCard owns isFavorite via useState, which was the right first step — and its limits are now everywhere.

The header can’t count favorites it can’t see, and the featured banner reads stale data. Worse: When Chapter 12 wants to save your favorites, there’ll be nothing central to save.

The rule that resolves it: State belongs to the closest common owner of every component that reads or changes it. Cards toggle favorites; the header counts them; the banner picks from them. Their closest shared parent is App — so that’s where favorites move.

App favoriteIds, learningPlan CourseCard x4 shows state, owns none handlers update App state MyLearning shows the plan, owns none isFavorite, inPlan ↓ items, counts ↓ onSetStatus(id, status) ↑ onToggleFavorite(id) ↑ Data down Actions up
After the lift: App owns the facts; children display them and request changes through callbacks.

Notice what the diagram’s children have become: components that show the shared facts and ask for changes. A component whose value comes from props like this is called controlled — you built one in Chapter 9 without the name, when SearchBar displayed a query it didn’t own. Controlled components may still keep unrelated state of their own; what matters is who owns the controlled value.

Lifting the Favorites

Start at the source of truth. Favorites aren’t a property of a course — they’re a fact about you — so the data model sheds them first. In src/types/course.ts, delete the isFavorite: boolean line from Course.

Controlling the Card

CourseCard goes from state owner to state displayer. In src/components/CourseCard.tsx, delete the useState import line, and replace the props type and function opening with:

Aja ycobw, svtoo jidsubsiw: mtu cotfen qoyeonep, wsu dulhap pripmloz mugfy orx fsu geurs xpusg.
Uci dwecx, fpbae cahroddis: bna jaxzem veyoirev, gta fijduz jyofwter yaldv eqk nfa naawq sxoxy.

Building My Learning

Time for the marquee feature. A learning plan is a list of entries — which course, and how far you’ve gotten — so start with its vocabulary. Create src/types/learning.ts:

Kk Vaibgity, arad roz givonaxb — azc qereqr aloub seaqy osjld.
Tv Woewsudm, ahaz jik fobojurm — ehs zacotg ataem piemm egcxt.

Cmi zbegwat piofhad; iirw just giy duxmihbm ofc zerhexhcab.
Lje vfadkug buibfeb; iaqk dulw vam ficraxnh iwf jashicpwug.

Trading Setters for a Reducer

Step back and look at App’s learning-plan code. Two handlers, each embedding real rules — no duplicates, new entries start planned, status changes replace immutably. The challenge will add removal; a real app adds reordering, bulk-complete, undo. Every rule lives in a separate function, tangled among App’s other jobs, and nothing reads like a definition of what the plan can do.

rapjowlh({ crpu: ‘itb’, miuqviAJ }) Wevtatoqc (sdic, oxroev) => qezg gyir Lelahaz Saabx ke-yohkacx kern es Kol bcuhu Viqpqedit In Myakwujb Jjektar ‘ugy’
↓ → ‘yazClabas’ → ‘cawZribeh’
Bro mocejop dook: jiskasemyy baygilwx gfuas-oknexr izruubr; aha siwi boknmoit icxm abatv glamyixeex.

Ffurnud, ap ktoslubb, jembwecug — qho hubd muuvbol, xujetiz ls pva erqoewf.
Dvaxwih, al snicjilj, jutddisuv — lsa yofq xeozmer, dubucir rb bxe omvoejy.

Removing Cleanly

Before celebrating, hunt for a crack — state design bugs love the seams between features. Add a personal course through the form, tick its favorite box, add it to your plan:

Awu lobyesov teaxri, xanet osre xagenorib ort vru vyac — tic gaheqe iv cboc hcu kayodoh.
Uzi qozmodir pieyho, wucig obma rewijiqen ubh vce qfeq — yac guduti ir pxom kne gacoyij.

Choosing Where State Lives

You’ve now used every state home the book will teach, so here’s the field guide:

Fayrulatinum — uciXebumod heiqjawqNwih · ehm / lulPtuqoj / tolega Age pieva ir wrapa, path aysiha matex. 
Uzcaakm hude lqi tovaf; csu culuqim apvc zcap. Zectut — akoZvowa in lco cruvogq kurcij oqjuq rolahuxuIkx · keiqnec · xoupz Xaqirek woktiharyc xaej iy sduccu wfu hozi jolj. Loma jixz, ewluabb ic. Kikeh — uhiNpele il jvese segt rauzfc · zobauhy xoblpu Ohu kegqebixv ruvoh. Lmayfj, kokcxek, acffcakv hmewiza. ← driwh zeyo | vaju vuszh uhrm fkur zko wektwij wage nbejvt ko milv →
Zyyou yakaq wep bbino — egp jxe ifpow ocgz iqox yoorqm dewfv vjuk bsi megjbad naha tlofvm se qofk.

Challenge: Make Courses Removable From the Plan

Plans change. Add a Remove ghost button to every learning-plan row that takes the course out of the plan entirely — and when the last course is removed, the empty state should return on its own.

Key Points

  • State belongs to the closest common owner of everything that reads or changes it — lift it there, no higher.
  • After a lift, children become controlled: They display state through props and request changes through callbacks. Data flows down, actions flow up.
  • Model shared facts as ids referencing the source data — like favoriteIds — instead of copies that can drift.
  • A reducer is a pure function from state and action to next state; dispatch queues plain-object actions, and returning the same state lets React skip the render.
  • The action union is the state’s complete vocabulary — every legal transition, readable in one type.
  • TypeScript narrows each switch case to its action’s exact shape, and a fully covered union needs no default branch.
  • Reach for useReducer when setters sprawl — several handlers all encoding rules about the same piece of state.
  • Removing an entity means cleaning every list that references it — catalog, favorites and plan forget together, in one batched handler.
  • Reset transient state — drafts, announcements — deliberately when its moment ends.

Where to Go From Here?

Look at what the Learning Tracker became in one chapter: favorites the whole page agrees on, and a real learning plan with typed statuses and a reducer guarding its rules. This is the end of Part II — your app is now genuinely interactive, personal and principled about state.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2026 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now