[{"data":1,"prerenderedAt":979},["ShallowReactive",2],{"page-\u002Freact\u002F26-exercises-and-projects":3},{"id":4,"title":5,"body":6,"description":972,"extension":973,"meta":974,"navigation":467,"path":975,"seo":976,"stem":977,"__hash__":978},"content\u002Freact\u002F26-exercises-and-projects.md","26 — Exercises & Projects",{"type":7,"value":8,"toc":939},"minimark",[9,13,17,22,27,43,47,59,63,75,79,99,103,118,122,126,141,145,161,165,177,181,196,200,216,220,224,232,236,248,252,279,283,307,311,339,343,347,367,371,390,394,407,411,420,424,436,440,822,826,854,858,935],[10,11,5],"h1",{"id":12},"_26-exercises-projects",[14,15,16],"p",{},"Reading twenty-five chapters builds vocabulary; building things builds judgment. Each exercise and project references the chapters where the relevant concepts are covered — hit a wall, then go back to that chapter. The wall is where the learning happens.",[18,19,21],"h2",{"id":20},"beginner-exercises","Beginner Exercises",[23,24,26],"h3",{"id":25},"_1-toggle-button","1. Toggle Button",[14,28,29,33,34,38,39,42],{},[30,31,32],"strong",{},"Requirements",": A button that toggles between \"ON\" and \"OFF\" states using ",[35,36,37],"code",{},"useState"," (Ch 3).\n",[30,40,41],{},"Stretch",": Add a second button that resets to OFF and disables itself when already OFF (Ch 4 conditional rendering).",[23,44,46],{"id":45},"_2-name-form","2. Name Form",[14,48,49,51,52,55,56,58],{},[30,50,32],{},": A controlled input that displays a greeting (",[35,53,54],{},"Hello, {name}!",") below it as the user types (Ch 5 controlled components).\n",[30,57,41],{},": Disable the greeting when the input is empty; show a character count (Ch 9 derived state).",[23,60,62],{"id":61},"_3-color-picker","3. Color Picker",[14,64,65,67,68,70,71,74],{},[30,66,32],{},": Three range inputs (R, G, B) that update a div's background color in real-time (Ch 3 + inline styles).\n",[30,69,41],{},": Display the hex color code using ",[35,72,73],{},"useMemo"," so it only recalculates when RGB values change (Ch 9).",[23,76,78],{"id":77},"_4-item-list","4. Item List",[14,80,81,83,84,86,87,90,91,94,95,98],{},[30,82,32],{},": Add items to a list via an input + button; delete items with an \"×\" button per item (Ch 6 list rendering + keys).\n",[30,85,41],{},": Persist the list to ",[35,88,89],{},"localStorage"," with a ",[35,92,93],{},"useEffect"," cleanup (Ch 6 + Ch 11 ",[35,96,97],{},"useLocalStorage"," hook).",[23,100,102],{"id":101},"_5-digital-clock","5. Digital Clock",[14,104,105,107,108,111,112,114,115,117],{},[30,106,32],{},": Display the current time, updating every second with ",[35,109,110],{},"setInterval"," inside ",[35,113,93],{}," (Ch 6 cleanup).\n",[30,116,41],{},": Add a 12\u002F24-hour format toggle and stop the interval when a \"Pause\" button is pressed (Ch 6 + Ch 8 refs for interval ID).",[18,119,121],{"id":120},"intermediate-exercises","Intermediate Exercises",[23,123,125],{"id":124},"_6-searchable-list-with-debounce","6. Searchable List with Debounce",[14,127,128,130,131,134,135,137,138,140],{},[30,129,32],{},": Filter a list of 100+ items by a search query, debounced 300ms using a ",[35,132,133],{},"useDebounce"," custom hook (Ch 11).\n",[30,136,41],{},": Memoize the filtered list with ",[35,139,73],{}," and verify via React DevTools Profiler that non-matching items don't re-render (Ch 9 + Ch 15).",[23,142,144],{"id":143},"_7-accordion-component","7. Accordion Component",[14,146,147,149,150,152,153,156,157,160],{},[30,148,32],{},": A collapsible accordion with multiple sections; only one section open at a time (Ch 4 conditional rendering + Ch 7 state lifting).\n",[30,151,41],{},": Make it accessible — keyboard navigable (arrow keys, Enter\u002FSpace), correct ARIA roles (",[35,154,155],{},"aria-expanded",", ",[35,158,159],{},"aria-controls","), and animate with CSS transitions (Ch 14).",[23,162,164],{"id":163},"_8-fetch-display-with-abort","8. Fetch + Display with Abort",[14,166,167,169,170,172,173,176],{},[30,168,32],{},": Fetch data from a public API; cancel the in-flight request if the user clicks \"Refresh\" before the first resolves (Ch 6 + Ch 17 AbortController).\n",[30,171,41],{},": Extract the fetch logic into a ",[35,174,175],{},"useFetch"," hook with loading\u002Ferror\u002Fsuccess states and use it for a second data source (Ch 11 + Ch 17).",[23,178,180],{"id":179},"_9-theme-toggle-with-context","9. Theme Toggle with Context",[14,182,183,185,186,188,189,191,192,195],{},[30,184,32],{},": A light\u002Fdark theme toggle that applies a CSS class to the app root via Context (Ch 7); persists the choice to ",[35,187,89],{},".\n",[30,190,41],{},": Add a ",[35,193,194],{},"useTheme"," hook that throws if used outside the provider, and consume it in three sibling components (Ch 7 + Ch 11).",[23,197,199],{"id":198},"_10-usereducer-cart","10. useReducer Cart",[14,201,202,204,205,208,209,211,212,215],{},[30,203,32],{},": A shopping cart with add\u002Fremove\u002Fadjust-quantity actions using ",[35,206,207],{},"useReducer"," (Ch 10); display total price and item count.\n",[30,210,41],{},": Convert to TypeScript with a discriminated-union action type and exhaustiveness check in the reducer's ",[35,213,214],{},"default"," case (Ch 23).",[18,217,219],{"id":218},"advanced-exercises","Advanced Exercises",[23,221,223],{"id":222},"_11-virtualized-list","11. Virtualized List",[14,225,226,228,229,231],{},[30,227,32],{},": Render 10,000 rows but only mount the visible ones in the viewport using windowing (Ch 20 performance); scroll position drives which rows render.\n",[30,230,41],{},": Add dynamic row heights (measure with a ref) and compare frame rate with\u002Fwithout virtualization using the Profiler (Ch 15 + Ch 20).",[23,233,235],{"id":234},"_12-optimistic-updates","12. Optimistic Updates",[14,237,238,240,241,243,244,247],{},[30,239,32],{},": A \"Like\" button that updates the count immediately and rolls back if the simulated server request fails (Ch 17 optimistic UI).\n",[30,242,41],{},": Add a 2-second artificial delay and show a \"Saving…\" indicator while the request is in-flight using ",[35,245,246],{},"useTransition"," (Ch 21).",[23,249,251],{"id":250},"_13-polymorphic-component","13. Polymorphic Component",[14,253,254,256,257,260,261,264,265,267,268,271,272,275,276,278],{},[30,255,32],{},": A ",[35,258,259],{},"\u003CBox as=\"button\" | \"a\" | \"div\">"," component in TypeScript that types its props correctly based on the ",[35,262,263],{},"as"," prop (Ch 23 polymorphic components).\n",[30,266,41],{},": Add ",[35,269,270],{},"forwardRef"," support and verify that ",[35,273,274],{},"ref"," is correctly typed for each ",[35,277,263],{}," variant (Ch 8 + Ch 23).",[23,280,282],{"id":281},"_14-test-a-component-suite","14. Test a Component Suite",[14,284,285,287,288,291,292,295,296,298,299,302,303,306],{},[30,286,32],{},": Write 5+ tests for a ",[35,289,290],{},"TodoItem"," component using RTL + ",[35,293,294],{},"userEvent",": render, toggle, delete, edit mode, and accessibility (Ch 24).\n",[30,297,41],{},": Mock a ",[35,300,301],{},"useTodos"," hook with ",[35,304,305],{},"vi.mock"," and test the component in isolation from the hook's implementation (Ch 24 mocking).",[23,308,310],{"id":309},"_15-sanitize-rich-text","15. Sanitize Rich Text",[14,312,313,315,316,319,320,322,323,326,327,330,331,334,335,338],{},[30,314,32],{},": A component that renders user-submitted Markdown as HTML via ",[35,317,318],{},"dangerouslySetInnerHTML",", sanitized with DOMPurify (Ch 25).\n",[30,321,41],{},": Add URL validation in the sanitizer's ",[35,324,325],{},"afterSanitizeAttributes"," hook — strip any ",[35,328,329],{},"href"," that isn't ",[35,332,333],{},"http:"," or ",[35,336,337],{},"https:"," (Ch 25).",[18,340,342],{"id":341},"project-ideas","Project Ideas",[23,344,346],{"id":345},"project-1-todo-app-with-sync-beginner-intermediate","Project 1 — Todo App with Sync (Beginner → Intermediate)",[14,348,349,350,353,354,356,357,191,360,362,363,366],{},"A full-featured todo app with local persistence, filtering, and a simulated sync to a backend.\n",[30,351,352],{},"Beginner tier",": Add\u002Fcomplete\u002Fdelete\u002Ffilter todos, persist to ",[35,355,89],{}," (Ch 3, 6, 11).\n",[30,358,359],{},"Intermediate tier",[35,361,207],{}," for state management, optimistic sync with rollback on failure, and a ",[35,364,365],{},"useSyncExternalStore"," adapter for cross-tab sync (Ch 10, 17, 18).",[23,368,370],{"id":369},"project-2-e-commerce-product-catalog-intermediate","Project 2 — E-Commerce Product Catalog (Intermediate)",[14,372,373,374,377,378,381,382,385,386,389],{},"A product catalog with routing, cart, filtering, and pagination.\n",[30,375,376],{},"Core",": Product list + detail pages via React Router, cart state via Context, URL query params for filters (Ch 7, 19).\n",[30,379,380],{},"Advanced",": Lazy-load the detail route with ",[35,383,384],{},"React.lazy"," + ",[35,387,388],{},"Suspense",", move cart to Zustand\u002FRedux Toolkit, add optimistic \"add to cart\" (Ch 18, 21).",[23,391,393],{"id":392},"project-3-real-time-chat-intermediate-advanced","Project 3 — Real-Time Chat (Intermediate → Advanced)",[14,395,396,397,399,400,402,403,406],{},"A WebSocket-based chat with message history, typing indicators, and auto-scroll.\n",[30,398,376],{},": WebSocket connection, message list, send on Enter, auto-scroll to newest (Ch 6, 8).\n",[30,401,380],{},": Virtualize the message list at 1000+ messages, debounce typing indicators, reproduce and fix a stale-closure bug in the ",[35,404,405],{},"onmessage"," handler (Ch 8, 20, 21).",[23,408,410],{"id":409},"project-4-component-library-with-typescript-tests-advanced","Project 4 — Component Library with TypeScript + Tests (Advanced)",[14,412,413,414,416,417,419],{},"A reusable component library (Button, Modal, Select, Tabs, DataTable) with full type safety and test coverage.\n",[30,415,376],{},": 8+ components with TypeScript generics, prop types exported, Storybook documentation (Ch 23).\n",[30,418,380],{},": Full RTL test suite covering keyboard navigation, visual regression tests, accessibility audit (focus trap in Modal, ARIA on Tabs), publish to a private npm registry (Ch 14, 24).",[23,421,423],{"id":422},"project-5-server-rendered-blog-with-streaming-advanced","Project 5 — Server-Rendered Blog with Streaming (Advanced)",[14,425,426,427,429,430,432,433,435],{},"A Next.js (or RSC framework) blog with Server Components, streaming, and SEO.\n",[30,428,376],{},": Post list + detail pages with server-side data fetching, one interactive island (comments) as a Client Component, ",[35,431,388],{}," streaming for slow data (Ch 22).\n",[30,434,380],{},": ISR with revalidation, Core Web Vitals measurement (LCP\u002FCLS) before and after moving sections to Server Components, CSP header that blocks injected inline scripts (Ch 22, 25).",[18,437,439],{"id":438},"mastery-self-check-questions","Mastery Self-Check Questions",[441,442,445],"code-wrapper",{"filename":443,"language":444},"self-check.md","markdown",[446,447,451],"pre",{"className":448,"code":449,"language":444,"meta":450,"style":450},"language-markdown shiki shiki-themes github-light github-dark","# Answer these without looking up the answer. If you can't, revisit the chapter.\n\n## Hooks (Ch 3-11)\n1. Why does `useEffect` with `[]` deps not see the latest state? What are the two fixes? (Ch 6, 8)\n2. When does `useMemo` HURT performance instead of helping? (Ch 9)\n3. `useState` vs `useReducer`: when is each the right choice? (Ch 10)\n4. What's the difference between a custom hook returning a tuple vs an object? (Ch 11)\n\n## Performance (Ch 13, 15, 20, 21)\n5. Why do `keys` matter in reconciliation? What happens with index keys on a reordered list? (Ch 13)\n6. Name three causes of unnecessary re-renders and their fixes. (Ch 15)\n7. When is virtualization the wrong solution? (Ch 20)\n8. `useTransition` vs `useDeferredValue`: when do you use each? (Ch 21)\n\n## Architecture (Ch 7, 18, 19, 22)\n9. When does Context cause performance problems, and what's the alternative? (Ch 7, 18)\n10. Server Component vs Client Component: what determines the choice? (Ch 22)\n11. Code splitting: when does `React.lazy` not help? (Ch 21)\n\n## TypeScript (Ch 23)\n12. Why does `\u003CT,>` need a trailing comma in `.tsx`? (Ch 23)\n13. `ReactNode` vs `JSX.Element` for `children` — which and why? (Ch 23)\n14. What does the exhaustiveness check (`const _: never = action`) prevent? (Ch 23)\n\n## Testing (Ch 24)\n15. `getByText` vs `findByText`: when does each cause a flaky test? (Ch 24)\n16. Why is `userEvent` preferred over `fireEvent`? (Ch 24)\n17. When are snapshot tests harmful? (Ch 24)\n\n## Security (Ch 25)\n18. Name four places where JSX's auto-escaping does NOT protect you. (Ch 25)\n19. Why is `localStorage` a risky default for auth tokens? What's the alternative? (Ch 25)\n20. Why doesn't `url.startsWith('javascript:')` safely sanitize a URL? (Ch 25)\n","",[35,452,453,462,469,475,499,514,532,541,546,552,567,576,585,602,607,613,622,631,646,651,657,677,700,715,720,726,743,764,773,778,784,793,807],{"__ignoreMap":450},[454,455,458],"span",{"class":456,"line":457},"line",1,[454,459,461],{"class":460},"sXvq9","# Answer these without looking up the answer. If you can't, revisit the chapter.\n",[454,463,465],{"class":456,"line":464},2,[454,466,468],{"emptyLinePlaceholder":467},true,"\n",[454,470,472],{"class":456,"line":471},3,[454,473,474],{"class":460},"## Hooks (Ch 3-11)\n",[454,476,478,482,486,490,493,496],{"class":456,"line":477},4,[454,479,481],{"class":480},"sCrzJ","1.",[454,483,485],{"class":484},"ssxIu"," Why does ",[454,487,489],{"class":488},"snvgF","`useEffect`",[454,491,492],{"class":484}," with ",[454,494,495],{"class":488},"`[]`",[454,497,498],{"class":484}," deps not see the latest state? What are the two fixes? (Ch 6, 8)\n",[454,500,502,505,508,511],{"class":456,"line":501},5,[454,503,504],{"class":480},"2.",[454,506,507],{"class":484}," When does ",[454,509,510],{"class":488},"`useMemo`",[454,512,513],{"class":484}," HURT performance instead of helping? (Ch 9)\n",[454,515,517,520,523,526,529],{"class":456,"line":516},6,[454,518,519],{"class":480},"3.",[454,521,522],{"class":488}," `useState`",[454,524,525],{"class":484}," vs ",[454,527,528],{"class":488},"`useReducer`",[454,530,531],{"class":484},": when is each the right choice? (Ch 10)\n",[454,533,535,538],{"class":456,"line":534},7,[454,536,537],{"class":480},"4.",[454,539,540],{"class":484}," What's the difference between a custom hook returning a tuple vs an object? (Ch 11)\n",[454,542,544],{"class":456,"line":543},8,[454,545,468],{"emptyLinePlaceholder":467},[454,547,549],{"class":456,"line":548},9,[454,550,551],{"class":460},"## Performance (Ch 13, 15, 20, 21)\n",[454,553,555,558,561,564],{"class":456,"line":554},10,[454,556,557],{"class":480},"5.",[454,559,560],{"class":484}," Why do ",[454,562,563],{"class":488},"`keys`",[454,565,566],{"class":484}," matter in reconciliation? What happens with index keys on a reordered list? (Ch 13)\n",[454,568,570,573],{"class":456,"line":569},11,[454,571,572],{"class":480},"6.",[454,574,575],{"class":484}," Name three causes of unnecessary re-renders and their fixes. (Ch 15)\n",[454,577,579,582],{"class":456,"line":578},12,[454,580,581],{"class":480},"7.",[454,583,584],{"class":484}," When is virtualization the wrong solution? (Ch 20)\n",[454,586,588,591,594,596,599],{"class":456,"line":587},13,[454,589,590],{"class":480},"8.",[454,592,593],{"class":488}," `useTransition`",[454,595,525],{"class":484},[454,597,598],{"class":488},"`useDeferredValue`",[454,600,601],{"class":484},": when do you use each? (Ch 21)\n",[454,603,605],{"class":456,"line":604},14,[454,606,468],{"emptyLinePlaceholder":467},[454,608,610],{"class":456,"line":609},15,[454,611,612],{"class":460},"## Architecture (Ch 7, 18, 19, 22)\n",[454,614,616,619],{"class":456,"line":615},16,[454,617,618],{"class":480},"9.",[454,620,621],{"class":484}," When does Context cause performance problems, and what's the alternative? (Ch 7, 18)\n",[454,623,625,628],{"class":456,"line":624},17,[454,626,627],{"class":480},"10.",[454,629,630],{"class":484}," Server Component vs Client Component: what determines the choice? (Ch 22)\n",[454,632,634,637,640,643],{"class":456,"line":633},18,[454,635,636],{"class":480},"11.",[454,638,639],{"class":484}," Code splitting: when does ",[454,641,642],{"class":488},"`React.lazy`",[454,644,645],{"class":484}," not help? (Ch 21)\n",[454,647,649],{"class":456,"line":648},19,[454,650,468],{"emptyLinePlaceholder":467},[454,652,654],{"class":456,"line":653},20,[454,655,656],{"class":460},"## TypeScript (Ch 23)\n",[454,658,660,663,665,668,671,674],{"class":456,"line":659},21,[454,661,662],{"class":480},"12.",[454,664,485],{"class":484},[454,666,667],{"class":488},"`\u003CT,>`",[454,669,670],{"class":484}," need a trailing comma in ",[454,672,673],{"class":488},"`.tsx`",[454,675,676],{"class":484},"? (Ch 23)\n",[454,678,680,683,686,688,691,694,697],{"class":456,"line":679},22,[454,681,682],{"class":480},"13.",[454,684,685],{"class":488}," `ReactNode`",[454,687,525],{"class":484},[454,689,690],{"class":488},"`JSX.Element`",[454,692,693],{"class":484}," for ",[454,695,696],{"class":488},"`children`",[454,698,699],{"class":484}," — which and why? (Ch 23)\n",[454,701,703,706,709,712],{"class":456,"line":702},23,[454,704,705],{"class":480},"14.",[454,707,708],{"class":484}," What does the exhaustiveness check (",[454,710,711],{"class":488},"`const _: never = action`",[454,713,714],{"class":484},") prevent? (Ch 23)\n",[454,716,718],{"class":456,"line":717},24,[454,719,468],{"emptyLinePlaceholder":467},[454,721,723],{"class":456,"line":722},25,[454,724,725],{"class":460},"## Testing (Ch 24)\n",[454,727,729,732,735,737,740],{"class":456,"line":728},26,[454,730,731],{"class":480},"15.",[454,733,734],{"class":488}," `getByText`",[454,736,525],{"class":484},[454,738,739],{"class":488},"`findByText`",[454,741,742],{"class":484},": when does each cause a flaky test? (Ch 24)\n",[454,744,746,749,752,755,758,761],{"class":456,"line":745},27,[454,747,748],{"class":480},"16.",[454,750,751],{"class":484}," Why is ",[454,753,754],{"class":488},"`userEvent`",[454,756,757],{"class":484}," preferred over ",[454,759,760],{"class":488},"`fireEvent`",[454,762,763],{"class":484},"? (Ch 24)\n",[454,765,767,770],{"class":456,"line":766},28,[454,768,769],{"class":480},"17.",[454,771,772],{"class":484}," When are snapshot tests harmful? (Ch 24)\n",[454,774,776],{"class":456,"line":775},29,[454,777,468],{"emptyLinePlaceholder":467},[454,779,781],{"class":456,"line":780},30,[454,782,783],{"class":460},"## Security (Ch 25)\n",[454,785,787,790],{"class":456,"line":786},31,[454,788,789],{"class":480},"18.",[454,791,792],{"class":484}," Name four places where JSX's auto-escaping does NOT protect you. (Ch 25)\n",[454,794,796,799,801,804],{"class":456,"line":795},32,[454,797,798],{"class":480},"19.",[454,800,751],{"class":484},[454,802,803],{"class":488},"`localStorage`",[454,805,806],{"class":484}," a risky default for auth tokens? What's the alternative? (Ch 25)\n",[454,808,810,813,816,819],{"class":456,"line":809},33,[454,811,812],{"class":480},"20.",[454,814,815],{"class":484}," Why doesn't ",[454,817,818],{"class":488},"`url.startsWith('javascript:')`",[454,820,821],{"class":484}," safely sanitize a URL? (Ch 25)\n",[18,823,825],{"id":824},"suggested-approach","Suggested Approach",[827,828,829,836,842,848],"ul",{},[830,831,832,835],"li",{},[30,833,834],{},"Beginner exercises (1-5)",": Build all five in one session — they exercise Ch 3-6 fundamentals.",[830,837,838,841],{},[30,839,840],{},"Intermediate exercises (6-10)",": Pick three that touch your weakest chapters.",[830,843,844,847],{},[30,845,846],{},"Advanced exercises (11-15)",": These force engagement with Ch 20-25 — don't skip them.",[830,849,850,853],{},[30,851,852],{},"Projects",": Pick one per tier (beginner, intermediate, advanced). The advanced project is where the hardest lessons (stale closures, reconciliation, server\u002Fclient boundaries, security gaps) actually stick.",[18,855,857],{"id":856},"key-takeaways","Key Takeaways",[441,859,862],{"filename":860,"language":861},"takeaways.js","javascript",[446,863,866],{"className":864,"code":865,"language":861,"meta":450,"style":450},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F 1. Exercises 1-5 → Ch 3-6: useState, controlled inputs, list rendering, useEffect cleanup.\n\u002F\u002F    If these are hard, re-read Ch 3-6 before moving on.\n\n\u002F\u002F 2. Exercises 6-10 → Ch 7-11: Context, useReducer, custom hooks, debounce, memoization.\n\u002F\u002F    These bridge from \"components work\" to \"components are well-architected.\"\n\n\u002F\u002F 3. Exercises 11-15 → Ch 20-25: Virtualization, optimistic UI, TS generics, testing, security.\n\u002F\u002F    These are the topics that separate mid-level from senior React engineers.\n\n\u002F\u002F 4. Projects 1-5: Full applications that force you to combine multiple chapters.\n\u002F\u002F    Project 5 (SSR blog) is the capstone — it exercises Ch 22 + 25 together.\n\n\u002F\u002F 5. Self-check questions: if you can answer all 20 without looking up, you've mastered\n\u002F\u002F    the curriculum. If not, the chapter reference tells you exactly where to go back.\n",[35,867,868,874,879,883,888,893,897,902,907,911,916,921,925,930],{"__ignoreMap":450},[454,869,870],{"class":456,"line":457},[454,871,873],{"class":872},"sdCPZ","\u002F\u002F 1. Exercises 1-5 → Ch 3-6: useState, controlled inputs, list rendering, useEffect cleanup.\n",[454,875,876],{"class":456,"line":464},[454,877,878],{"class":872},"\u002F\u002F    If these are hard, re-read Ch 3-6 before moving on.\n",[454,880,881],{"class":456,"line":471},[454,882,468],{"emptyLinePlaceholder":467},[454,884,885],{"class":456,"line":477},[454,886,887],{"class":872},"\u002F\u002F 2. Exercises 6-10 → Ch 7-11: Context, useReducer, custom hooks, debounce, memoization.\n",[454,889,890],{"class":456,"line":501},[454,891,892],{"class":872},"\u002F\u002F    These bridge from \"components work\" to \"components are well-architected.\"\n",[454,894,895],{"class":456,"line":516},[454,896,468],{"emptyLinePlaceholder":467},[454,898,899],{"class":456,"line":534},[454,900,901],{"class":872},"\u002F\u002F 3. Exercises 11-15 → Ch 20-25: Virtualization, optimistic UI, TS generics, testing, security.\n",[454,903,904],{"class":456,"line":543},[454,905,906],{"class":872},"\u002F\u002F    These are the topics that separate mid-level from senior React engineers.\n",[454,908,909],{"class":456,"line":548},[454,910,468],{"emptyLinePlaceholder":467},[454,912,913],{"class":456,"line":554},[454,914,915],{"class":872},"\u002F\u002F 4. Projects 1-5: Full applications that force you to combine multiple chapters.\n",[454,917,918],{"class":456,"line":569},[454,919,920],{"class":872},"\u002F\u002F    Project 5 (SSR blog) is the capstone — it exercises Ch 22 + 25 together.\n",[454,922,923],{"class":456,"line":578},[454,924,468],{"emptyLinePlaceholder":467},[454,926,927],{"class":456,"line":587},[454,928,929],{"class":872},"\u002F\u002F 5. Self-check questions: if you can answer all 20 without looking up, you've mastered\n",[454,931,932],{"class":456,"line":604},[454,933,934],{"class":872},"\u002F\u002F    the curriculum. If not, the chapter reference tells you exactly where to go back.\n",[936,937,938],"style",{},"html pre.shiki code .sXvq9, html code.shiki .sXvq9{--shiki-default:#005CC5;--shiki-default-font-weight:bold;--shiki-github-dark:#79B8FF;--shiki-github-dark-font-weight:bold}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}",{"title":450,"searchDepth":464,"depth":464,"links":940},[941,948,955,962,969,970,971],{"id":20,"depth":464,"text":21,"children":942},[943,944,945,946,947],{"id":25,"depth":471,"text":26},{"id":45,"depth":471,"text":46},{"id":61,"depth":471,"text":62},{"id":77,"depth":471,"text":78},{"id":101,"depth":471,"text":102},{"id":120,"depth":464,"text":121,"children":949},[950,951,952,953,954],{"id":124,"depth":471,"text":125},{"id":143,"depth":471,"text":144},{"id":163,"depth":471,"text":164},{"id":179,"depth":471,"text":180},{"id":198,"depth":471,"text":199},{"id":218,"depth":464,"text":219,"children":956},[957,958,959,960,961],{"id":222,"depth":471,"text":223},{"id":234,"depth":471,"text":235},{"id":250,"depth":471,"text":251},{"id":281,"depth":471,"text":282},{"id":309,"depth":471,"text":310},{"id":341,"depth":464,"text":342,"children":963},[964,965,966,967,968],{"id":345,"depth":471,"text":346},{"id":369,"depth":471,"text":370},{"id":392,"depth":471,"text":393},{"id":409,"depth":471,"text":410},{"id":422,"depth":471,"text":423},{"id":438,"depth":464,"text":439},{"id":824,"depth":464,"text":825},{"id":856,"depth":464,"text":857},"Capstone exercises and project ideas spanning beginner, intermediate, and advanced levels. 15 exercises (5 per tier) with Requirements + Stretch, 5 full project ideas, and mastery self-check questions. References earlier chapters for deeper exploration.","md",{},"\u002Freact\u002F26-exercises-and-projects",{"title":5,"description":972},"react\u002F26-exercises-and-projects","h8HdVNSpPTqW4E16bW9mkY3Yw7Az9HV1UvaXxlSUTfg",1789924652689]