Share an order across islands with the store
For developers who have built a page with a loader and placed an island and want several islands on one page to agree on the same values
You'll build a coffee order page. A loader seeds the size, the price and the quantity. One island picks the size, one steps the quantity and one shows the total. None of them pass props to each other: they read and write keys in the store, the server renders the first paint from the same keys and a derived key computes the total on both sides.
Before you start
You need Rust with Cargo. Install snapfire_fsr_cli from crates.io:
cargo install snapfire_fsr_cliSet up the project#
Start a bare application and add React:
The route for this tutorial is /order. Make its directory now:
Name the keys#
A key is a branded string. Name every key the page shares in one module, so an island and a loader cannot disagree on the spelling or the type:
;
;
;
;
;Seed the keys from the loader#
The page loader returns the bag of beans and its sizes. Its store export turns that data into the first values of the keys. The server renders the page from these values and the browser starts from the same ones, so the first paint and the hydration agree:
;
;
;Every key the loader seeds is a starting point. An island may write any of them afterwards and its write stands until the page loads again.
Compute the total once, for both sides#
derive names a key that is computed from others. The browser recomputes it whenever a source changes. The server computes it the same way before it renders, so the total is right on the first paint:
;
;
total,,price ?? 0 * qty ?? 0;app/src/main.ts is the application's entry module. The server runs its derive when it renders and the browser runs it when the module loads.
Pick the size#
The first island reads the size and writes two keys at once when a button is clicked. transaction collapses the two writes into one notification, so a reader of both sees them together:
;
;
;
useStore(size, fallback) reads like useState. The fallback is what the component shows while nothing has set the key, which never happens on this page since the loader seeds it, but the component is honest about the case either way.
Step the quantity#
The second island writes the quantity and tells the server about it. optimistic sets the key at once, runs the action and puts the key back if the action fails:
;
;
;;
;
;
;
;
The action's answer revalidates the route, so the loader runs again and seeds the keys again. A key the visitor wrote keeps the visitor's value.
Show the total#
The third island only reads. It reads the derived key like any other:
;
;
Place the islands on the page#
The page places the three islands. Each is its own root in the browser; the store is what joins them:
;
;
;
;
;
Run it#
Open /order. The page arrives with 250g, a quantity of 1 and Total: $12 already in the markup; nothing waits for JavaScript to show a number. Click 1kg: the size and the price move together and the total reads $40. Click + twice: the quantity reads 3 and the total $120. The session holds the quantity the two round trips set. Reload the page: the loader seeds the keys again and the quantity the visitor chose is still there.
Test it#
A page spec renders the route with its loader and drives the islands the way a visitor would:
;
;
"moves the total when the size and the quantity change",
;What you built#
Three islands, no props between them. The loader seeds the store, the server renders the first paint from the seeds, a derived key computes the total on both sides and the islands write the keys they own. Adding a fourth island that reads the price is one useStore away.
