Checkout

Events

Complex Interactive Server (prerendered)

A storefront with a root cart and a self-contained checkout flow. It combines named scopes, async handlers, error isolation and state carried over from prerendering.

How it works

Try it: reload the page and read the note under the cart. Go through checkout, and once with an email containing crash.

  • Prerender persistence. SavedCartLoader fills CartState during prerendering. PersistState(…CartState) serializes it into the page, and the interactive circuit restores it instead of loading again. The time in the note is when the load ran: it stays at the page's load time, because the interactive circuit does not load a second time.
  • Root vs. scoped state. CartState lives at the root and is shared by the catalog, badge, summary and checkout. CheckoutForm lives in the checkout's StateScope.
  • Named route. Place order publishes OrderSubmitted with Route.Named("checkout", Broadcast). The order log outside the scope never sees it (its counter stays 0).
  • Async handler + cancellation. PaymentProcessor awaits a fake payment with the handler's CancellationToken, which is cancelled if you navigate away. It then publishes OrderConfirmed, which bubbles up to the order log.
  • Error isolation. With an email containing crash, AnalyticsTracker throws. Its ErrorBoundary shows the error while the payment still completes.
  • Events + selectors. CartBadge re-renders for count changes (selector) and pulses on ItemAdded (event).

Products

🛒 3 renders: 2
☕
Coffee beans
¤14.50
🥐
Croissant
¤3.25
🥑
Avocado
¤1.90
🧀
Cheese board
¤18.00
🍋
Lemonade
¤4.75
🍫
Chocolate
¤6.20

Cart

☕ Coffee beans × 1 ¤14.50
🥐 Croissant × 2 ¤6.50
Saved cart loaded at 15:39:04. After the page becomes interactive this time does not change: PersistState<CartState>() carried the value over from prerendering.
  1. Address
  2. Payment
  3. Review

Order log (outside the checkout scope)

OrderSubmitted seen here: 0
No orders yet.
An unhandled error has occurred. Reload 🗙