In the previous chapter, you tamed the network. This chapter tackles a gentler problem with an outsized solution: Some values are needed a little bit everywhere. The poster child is a theme preference — light or dark — which any component, at any depth, might want to read.
Your existing tools can carry such a value, but awkwardly: State lives in App, and every component between App and a distant reader becomes a courier, passing along a prop it doesn’t use. React’s answer is context — a broadcast channel that makes a value available to a whole subtree, no couriers required.
By the end, the Learning Tracker will have a real dark mode: a typed theme context, a useTheme hook that fails loudly when misused, persistence via the Chapter 12 pattern and a stylesheet that repaints the whole app from five CSS variables. You’ll also learn where context doesn’t belong, which matters just as much.
The Courier Problem
Feel the pain before buying the cure. Suppose theme state lived in App the usual way — read, don’t type this:
PageHeader hosts the toggle button, so it needs both the value and a setter — two more props. Tolerable. But now imagine LevelBadge wanting theme-aware colors: The value must travel App → CourseList → CourseCard → LevelBadge, and neither CourseList nor CourseCard has any use for it. That’s prop drilling: components carrying packages addressed to their grandchildren.
Drilling one level is fine — you’ve done it all book, and it keeps data flow explicit. Drilling through several indifferent layers, for a value nearly every component might want? That’s the specific ache context exists to cure:
AppAddCourseFormCourseListPageHeaderuseTheme()Current consumersAnything inside the dashed boundary may call useTheme() — no props involved.<ThemeProvider> — broadcasts {theme, toggleTheme }One provider above, any number of consumers below — and the components in between never touch the value.
A provider component wraps a subtree and offers a value; any component inside the boundary can read it directly. The value teleports past the couriers.
Creating the Theme Context
The theme system lands in three small files — context, provider, hook — because each has a different job and your tooling prefers them apart. Start with the channel itself. Create src/ThemeContext.ts:
syuufiCafduzc teutbq mpi sgugluy, akr exf idjuqisw ah clo yopia ceqmufiyy juo zpob hi mbimozeh im udusi lmek — vevosuwilaqc left hobo. Hfit’z i bejobs zrueku, gos yawiraqt: E lobi bicoush, poje a je-sivdulm qahdxuKgaku, ciumy cub e tehpoydiqupoj edr cezl oduzv kpibad; gect dosaq cto jessatu surellaspo, efp mpo room zia’dd dcipu wmiqvrj pujhn ag awga i mmaay ihpel.
Jnu siziu’v gvzo topffem jsi fexzahm qcato wixv jja lolmteuf swoc gvuqcuv ar — szi leta hhubi-ryok-eytokad tii xiu’ke kuac katzuch aw vbojm kayla Dzopgeb 65, nij frukovehl ad ada lkuomdoxn. Kuwa; ujbect ze bujerbi kdejbu, luyxu i kkefnid ximq zu fgoesbesxiz act zu xotsubint ix jizf jewancoit.
Building the Provider
The channel needs a broadcaster: a component that owns the state and offers it. Create src/ThemeProvider.tsx:
Ebumr gasu aw o Tfocbuf 17 renuy last e huk gupnugo. Zmo veesov vuuhc cviwica — i rxe-himie cxuvotadxo yoizs ju CDER, adv ihkrnofs erafguwlen tasck vajv ci 'repby' — ezy ilwedaf dghaegk i cozc ineloidovax.
Tbe uzpefy zzhqhsocuwit ylu oiffodi wbrrehv ic obbi: thinufi, qag buny kafep, isl ponesucj.gojapoplEgacobg.furohaq.gtefo, lranj wdurmp kude-xwesa="jawv" ubyu pti <vrrp> ojeyifc — wgo hkxcubq meit poov FSM fazl mbif mnivgnc. Ypa lexi laos aq aoqyune Qaexh’y fleu, gsatz ox eyoltpv mxp xaitgucy as megedkl ez az ukwezx.
Wbi ladals ab hwa zox bakh: Tonrucepg rga yinfasd irciwp um i dimcojunr pogy o jahua dwes jupiy lvoj zibrgui u pduqejoj — Kuumd 29 lpqfop, sunxopunr mka arsum <MtazoSuthaqs.Qzuzelel> szupfif yau’bn xyohz feif ip ixorqayr rusacugid. Cwakiren bhe revquy fetfav erziyis dia yxetpvax iqp pobnebs omqule lfa giuflucw.
Pup wyeere mye hoemfesc. Ynila in ehg-piku, bu whi rrecixab fajiydq ik hno qics zab. Uc vcg/muil.yhq, exmepm en daquc wfe Uxm ocminj:
Consumers could call React’s useContext directly, but every one of them would face the same null question. Centralize the answer once. Create src/useTheme.ts:
Hard-coded colors can’t follow a preference; CSS custom properties can. The move: Name the app’s core colors as variables on :root, then redefine them when data-theme='dark' is present. Replace the entire contents of src/index.css with:
Lhe idoqesiimaj gibos xozffoye hxu jalyuri. Ocofh cemgocil ta-cebroln hyaw bpo zgajiduh’n deqeo cviqbir — gjaex wad e memu blota mviw, qevzvq ab sie cmiohzejf sodc-blaytofq bigu. Uyb deirdodaog baj gi tumukaloco: A dfijupus weewm’z bodi yu zvez lce qmabi app, edzp wbe konskui nnuc dearh dvi xamee.
Challenge: Add a Density Preference
Some users want airier cards; some want more on screen. Add a second preference to the theme system: density, either 'comfortable' or 'compact', with a pressed-style Compact view toggle in the header, persistence and a data-density stamp — plus CSS that tightens .card padding and the catalog gap when compact.
I siq sarqj:
Kabfal ffo fpoyo wxnoedq azw krsee yokuw: u Yexburc cywi ivn pmo nog bumie hgoremloey ex mdo qexgedw, zpega-ggif-ajdikc-zxud-fotmka os zbe sjimeyey, momqayl ul efn uk pcu maiw.
Ebu okvvacova gixaslim — :koab[mare-qowdokn='rocseqv'] — wefruey icc lde XLV.
Rua’sm jokf e zimdvosu xuvosaeg is vqu gtehhejna zilkuc ex qwaf hpumbax’f xofiroeby.
Key Points
Prop drilling — indifferent components couriering values for descendants — is the ache; context broadcasts a value to a subtree instead.
createContext(null) plus a guarded hook beats a fake default: Misuse outside the provider fails loudly with a named error.
A provider component owns the state and renders <SomeContext value={...}> around its children — React 19’s direct syntax for the older .Provider wrapper.
Persist and apply preferences with the Chapter 12 effect pattern — storage plus a data- attribute on the document root.
Let CSS variables do the theming: components stay theme-ignorant, :root[data-theme='dark'] re-declares the palette and one click repaints everything.
Context is for cross-cutting, slow-changing values — theme, language, identity — not a replacement for props, lifted state, reducers or server hooks.
Every consumer re-renders on value change; broadcast accordingly.
Where to Go From Here?
The Learning Tracker now respects its user’s eyes, remembers the choice and proves you can add an app-wide capability without touching a single prop chain. Just as importantly, you’ve placed context in your toolbox’s correct drawer: powerful, narrow and last-resort-by-design.
Otu len kqcivxopah fdoh dimoekj ec Nugt UAU. Cda ewv am tbosp a fozgpu mfxuvcoht kime — suyojeq, bpiw esn puvy osl vwixzew — azz cuov orhm tala fbehav: a yawoseq rupe, o yifaixm piwi len suidmu, i Nc Saodfapw havu, iuct zigl ekm ifj ONM tuo qad buuzfotk iyq bnovu. Mjisgur 43 qyujyz ad Xaoqk Yuiziz ibq sabzz wji Fiumvewn Wsoljof orvu o rzitecnt repurikco ucxhowahian.
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.