Build the safeguards
Eight explained steps, a source example and a checkpoint at each decision.
Read the tutorialReact / TypeScript / Product engineering
Change a reservation. Let the interface respond immediately. Then find out whether its editor, summary and server still agree.
An optimistic interface shows a proposed change before the server confirms it. A reliable interface also handles rejection, competing edits and every other view of the same record.
This is a real React application with a timed, in-memory server fixture. It demonstrates UI state and version checks; it does not connect to a reservation service or implement a production Next.js server.
Your independent testing environment
Run the rejected-save example first. Compare the three seat counts, then try the conflict and stale-summary examples. Further down, type a row note and test what happens when the rows reverse.
Loading the React reservation editor…
A rejected save returns the safeguarded editor to two seats. A competing edit preserves the server’s newer four-seat record. A successful save updates the safeguarded summary to three seats.
Open the exact source behind this edition. The viewer checks each file against its SHA-256 manifest and explains the decision it implements.
Eight explained steps, a source example and a checkpoint at each decision.
Read the tutorialUnderstand where each pattern helps and which tradeoffs remain.
Compare approachesDownload the independent environment, run the native checks and try a specific extension.
Open the how-to guideStart with Run and read the comparison. The tutorial introduces the code after you have seen the behavior. The how-to guide separates a no-install route from the native developer exercise.
Reset discards this lab’s temporary state and cancels or terminates its pending work. These examples use invented records. No account, production data or cloud deployment is needed.
This is a real React application with a timed, in-memory server fixture. It demonstrates UI state and version checks; it does not connect to a reservation service or implement a production Next.js server.
Lab discussion / React Reconciliation Lab
Ask about the code, compare an approach, or describe an edge case. Reader comments are reviewed before publication.
Code walkthrough
These short excerpts connect the lab’s behavior to its implementation. Each example links to the full tutorial step for its context, tradeoffs and checkpoint. Names and dependencies belong to that source; the excerpts are not standalone programs.
The fixture rejects six seats because its room limit is four. The broken implementation ignores that result and leaves six visible. The safeguarded implementation displays the confirmed record and a specific reason. In a larger editor you can preserve the rejected draft separately so the person can repair it.
if (!result.ok) {
editor = result.record;
message = result.reason;
}
The conflict example advances the server record to version two before your version-one save arrives. The safeguarded server compares the submitted version with its current version and rejects the stale write. In production this decision must be atomic in the backend; a browser-only comparison cannot prevent competing writes.
if (requested.version !== current.version) {
return {ok: false, record: current, reason: "Review newer version"};
}
The cache example accepts three seats. The broken editor updates, while its summary remains at two. The safeguard derives both from the confirmed result. A real query cache may invalidate a key or update a normalized entity; either way, enumerate the views whose meaning changed.
return {editor: result.record, summary: result.record};
React uses keys to match children across renders. Type a note beside Aster and reverse the two rows. An array-index key retains an uncontrolled input at its position, so the note appears beside the other person. A stable identifier retains the input with its record.
rows.map(person => (
<Row key={person.id} person={person} />
))
The pure save and reconciliation functions have regression tests. Browser checks cover the actual controls, input identity and resetting a pending timer. Keep those responsibilities distinct: a passing pure function test does not establish that the interface uses its result correctly.
const denied = saveOnServer(current, proposal, "rejected", true);
assert.equal(reconcile(current, proposal, denied, true).editor.seats, 2);