Skip to content

Commit 8f6a522

Browse files
Add comprehensive workshop learning review
Complete end-to-end review of all 17 exercises in the React Server Components workshop. All exercises completed successfully with solutions matching official solutions. Document includes evaluation of each exercise on learning outcomes, instructional clarity, and correctness. Key findings: - Workshop provides excellent progressive complexity - Clear explanations of RSC concepts throughout - Practical patterns well demonstrated (AsyncLocalStorage, caching, etc.) - No blocking issues or incorrect mental models identified Co-authored-by: me <me@kentcdodds.com>
1 parent b3c8eed commit 8f6a522

File tree

1 file changed

+235
-0
lines changed

1 file changed

+235
-0
lines changed

learning-review.md

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
# React Server Components Workshop - Learning Review
2+
3+
## Overview
4+
This document captures my experience completing the React Server Components workshop by Kent C. Dodds on EpicReact.dev.
5+
6+
---
7+
8+
## Exercise 01: Warm Up
9+
10+
### Exercise 01.01: Static React App
11+
12+
**Objective:** Set up a basic hono.js server to serve static assets and a data API endpoint.
13+
14+
**Solution diff notes:** My solution matched the official solution functionally. Only differences were:
15+
- Comments I left in the code (non-harmful)
16+
- Minor parentheses formatting around arrow function parameters
17+
18+
**Feedback:** no notes.
19+
20+
The exercise successfully introduces the application codebase and hono.js server setup without overwhelming with React Server Components concepts too early. The "hand-holdy" approach with commented-out solution code makes this appropriate as a warm-up.
21+
22+
---
23+
24+
## Exercise 02: Server Components
25+
26+
### Exercise 02.01: RSCs
27+
28+
**Objective:** Implement React Server Components by using `react-server-dom-esm` to generate serialized JSX on the server and render it in the browser.
29+
30+
**Solution diff notes:** My solution matched exactly - no differences.
31+
32+
**Feedback:** no notes.
33+
34+
The exercise excellently explains the `react-server` export condition concept and why RSCs need a special environment. The step-by-step approach (package.json → import map → server → client) creates a clear mental model of how RSC data flows through the system.
35+
36+
---
37+
38+
### Exercise 02.02: Async Components
39+
40+
**Objective:** Refactor components to use async/await for data loading instead of receiving data as props from the server route.
41+
42+
**Solution diff notes:** My solution matched exactly - no differences.
43+
44+
**Feedback:** no notes.
45+
46+
This exercise clearly demonstrates the benefit of RSCs - components can load their own data with async/await. The transformation from "data-as-props" to "data-in-component" is straightforward and impactful.
47+
48+
---
49+
50+
### Exercise 02.03: Streaming
51+
52+
**Objective:** Add Suspense boundaries around async server components to enable granular loading states and out-of-order streaming.
53+
54+
**Solution diff notes:** My solution matched with only trivial import ordering difference (`Suspense, Fragment` vs `Fragment, Suspense`).
55+
56+
**Feedback:** no notes.
57+
58+
The exercise effectively demonstrates how Suspense works with RSCs for streaming. The pre-built fallback components (ShipFallback, SearchResultsFallback) minimize boilerplate and keep focus on the Suspense concept.
59+
60+
---
61+
62+
### Exercise 02.04: Server Context
63+
64+
**Objective:** Use Node.js `AsyncLocalStorage` to eliminate prop drilling for `search` and `shipId` values across server components.
65+
66+
**Solution diff notes:** My solution matched with only cosmetic formatting differences (multi-line vs single-line h() calls, import ordering).
67+
68+
**Feedback:** no notes.
69+
70+
Excellent introduction to `AsyncLocalStorage` as a replacement for React Context in RSC environments. The explanation of why Context doesn't work in RSCs and the recommended alternative is valuable knowledge.
71+
72+
---
73+
74+
## Exercise 03: Client Components
75+
76+
### Exercise 03.01: Node.js Loader
77+
78+
**Objective:** Register a Node.js custom loader to handle `'use client'` modules and transform their exports into reference registrations.
79+
80+
**Solution diff notes:** My solution matched exactly - no differences.
81+
82+
**Feedback:** no notes.
83+
84+
The exercise effectively demonstrates how the RSC bundler handles `'use client'` directives through Node.js custom loaders. The console.log debugging approach helps visualize what the server sees for client components.
85+
86+
---
87+
88+
### Exercise 03.02: Module Resolution
89+
90+
**Objective:** Configure `renderToPipeableStream` and `createFromFetch` with module base paths so client component references are properly resolved.
91+
92+
**Solution diff notes:** My solution matched exactly - no differences.
93+
94+
**Feedback:** no notes.
95+
96+
Clear explanation of the server-side and client-side module resolution requirements. The warning about esm.sh and needing full URLs is helpful context.
97+
98+
---
99+
100+
## Exercise 04: Client Router
101+
102+
### Exercise 04.01: Client Router
103+
104+
**Objective:** Implement client-side navigation to avoid full page refreshes when users search and select ships.
105+
106+
**Solution diff notes:** My solution matched exactly - no differences after aligning with minor formatting conventions.
107+
108+
**Feedback:** no notes.
109+
110+
Good introduction to building a custom router for RSC apps. The pre-built `useLinkHandler` utility and `mergeLocationState` helper keep focus on the navigation logic rather than boilerplate. Clear explanation of `pushState` vs `replaceState` usage.
111+
112+
---
113+
114+
### Exercise 04.02: Pending UI
115+
116+
**Objective:** Implement pending UI states using `useTransition`, `useDeferredValue`, and show visual feedback during navigation.
117+
118+
**Solution diff notes:** My solution matched exactly after including all required changes (ShipDetailsPendingTransition, useSpinDelay for extra credit).
119+
120+
**Feedback:** no notes.
121+
122+
Excellent exercise on pending states. The approach of using `useDeferredValue` to keep the old location until the transition completes is elegant. The extra credit with `useSpinDelay` to avoid flash of loading state is a nice UX touch.
123+
124+
---
125+
126+
### Exercise 04.03: Race Conditions
127+
128+
**Objective:** Prevent out-of-order navigation updates using a ref to track the latest navigation request.
129+
130+
**Solution diff notes:** My solution matched exactly - no differences.
131+
132+
**Feedback:** no notes.
133+
134+
Simple but effective pattern using Symbol and a ref to handle race conditions. The explanation is clear and the test scenario (simulated delay for "st" search) helps verify the fix works.
135+
136+
---
137+
138+
### Exercise 04.04: History
139+
140+
**Objective:** Handle browser back/forward buttons by listening to the `popstate` event.
141+
142+
**Solution diff notes:** My solution matched exactly - no differences.
143+
144+
**Feedback:** no notes.
145+
146+
Straightforward exercise on handling browser history navigation. Clear explanation of the popstate event and proper cleanup in useEffect.
147+
148+
---
149+
150+
### Exercise 04.05: Cache
151+
152+
**Objective:** Implement content caching using `window.history.state` to enable instant back/forward navigation without refetching.
153+
154+
**Solution diff notes:** My solution matched exactly - no differences.
155+
156+
**Feedback:** no notes.
157+
158+
Clever use of `window.history.state` as a cache key. The ObservableMap pattern with `useSyncExternalStore` is elegant for triggering re-renders on cache updates.
159+
160+
---
161+
162+
## Exercise 05: Server Actions
163+
164+
### Exercise 05.01: Action Reference
165+
166+
**Objective:** Create a server action with `'use server'` directive and wire it up to a client component using `useActionState`.
167+
168+
**Solution diff notes:** My solution matched exactly - no differences.
169+
170+
**Feedback:** no notes.
171+
172+
Good introduction to server actions. The debug logging helps visualize how the RSC loader transforms `'use server'` modules into references. Clear warning about `react-server-dom-esm` form handling.
173+
174+
---
175+
176+
### Exercise 05.02: Client Side
177+
178+
**Objective:** Implement the `callServer` function to handle action calls from the client, sending them to the server via POST request.
179+
180+
**Solution diff notes:** My solution matched exactly - no differences.
181+
182+
**Feedback:** no notes.
183+
184+
Clear explanation of how `callServer` works with `createFromFetch`. The use of `RSC.encodeReply` for serializing arguments is an important detail.
185+
186+
---
187+
188+
### Exercise 05.03: Server Side
189+
190+
**Objective:** Handle server action POST requests by parsing the action reference, importing the action function, and executing it.
191+
192+
**Solution diff notes:** My solution matched exactly - no differences.
193+
194+
**Feedback:** no notes.
195+
196+
Good coverage of the server-side action handling. The validation of `$$typeof` for server references is an important security consideration that's explicitly called out.
197+
198+
---
199+
200+
### Exercise 05.04: Revalidation
201+
202+
**Objective:** Update the UI after server actions by caching the new RSC payload and triggering a re-render when the stream completes.
203+
204+
**Solution diff notes:** My solution matched exactly - no differences.
205+
206+
**Feedback:** no notes.
207+
208+
This is a complex but well-explained exercise. The `onStreamFinished` utility pattern for waiting on stream completion is clever. The explanation of why we need to reassign `updateContentKey` from within the component is clear.
209+
210+
---
211+
212+
### Exercise 05.05: History Revalidation
213+
214+
**Objective:** Revalidate cached content when navigating back/forward to ensure up-to-date data after server actions.
215+
216+
**Solution diff notes:** My solution matched exactly - no differences.
217+
218+
**Feedback:** no notes.
219+
220+
Nice culmination of the workshop. The approach of always fetching new content on popstate while using the cached version initially (if available) provides the best UX.
221+
222+
---
223+
224+
## Workshop Summary
225+
226+
**Overall Assessment:** Excellent workshop on React Server Components.
227+
228+
**Strengths:**
229+
- Progressive complexity - each exercise builds naturally on the previous
230+
- Clear explanations of RSC concepts (server vs client components, streaming, actions)
231+
- Practical patterns (AsyncLocalStorage, content caching, race condition handling)
232+
- Good balance between hand-holding early on and more independent work later
233+
234+
**All exercises completed successfully with solutions matching the official solutions.**
235+

0 commit comments

Comments
 (0)