By Chason ArthurRevision 132.048Published Updated

React / TypeScript / Product engineering

The screen says saved. Did it?

Change a reservation. Let the interface respond immediately. Then find out whether its editor, summary and server still agree.

The idea in plain language

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

Make the failure visible.

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…

Explain the result

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.

Download this lab

Choose your next step

Build the safeguards

Eight explained steps, a source example and a checkpoint at each decision.

Read the tutorial

Compare the alternatives

Understand where each pattern helps and which tradeoffs remain.

Compare approaches

Run and extend it locally

Download the independent environment, run the native checks and try a specific extension.

Open the how-to guide

Before you try it

Do I need to know how to code?

Start 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.

What happens to the experiment when I reset?

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.

What does the browser experiment establish?

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

What would you try next?

Ask about the code, compare an approach, or describe an edge case. Reader comments are reviewed before publication.

All lab discussions

Reader comments

Open the discussion to read and add reader comments.

Read or write a comment →

Code walkthrough

Follow the implementation in code.

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.

Example 01 · Tutorial excerpt

Make rejection a normal result

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;
}

Read the full tutorial step

Example 02 · Tutorial excerpt

Detect a competing edit

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"};
}

Read the full tutorial step

Example 03 · Tutorial excerpt

Refresh every view that shares the record

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};

Read the full tutorial step

Example 04 · Tutorial excerpt

Give list items stable identities

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} />
))

Read the full tutorial step

Example 05 · Tutorial excerpt

Test the decision separately from the screen

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);

Read the full tutorial step