-
In #754 (comment) @Rich-Harris wrote:
This sounds like I should be able to pass any object from In my particular case, I’m getting JSON from an endpoint and then using that to initialize an XState service, which I pass as a param to the page component from I’m using a pattern similar to https://github.com/annaghi/xstate-cameoparison-svelte-actors/blob/main/src/app/App.svelte#L17, but would like to pre-render the initial state on the server. (@annaghi) |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Apparently my error was between the chair and the keyboard. After some fiddling, here’s a summary of how I successfully wired everything up. The key insight was that XState actors (e.g. interpreted machines) are also Svelte stores. Passing stores between components allows you to let XState handle the relationships between the backing state, for example, The use case here is a classic collection-detail. Initially you get a list of available items. Selecting one shows its detail and allows the user to edit. This is mostly an exercise to understand how to plumb Svelte components with interrelated XState state machines managing state. You can see the working(ish) proof-of-concept at https://github.com/jmakeig/svelte-xstate-collection-details. Page componentGenerate the initial view on the server, wrapping the fetched data in a state machine. <script context="module">
import { createItemsStore } from './_itemsMachine';
export function load({ params, fetch }) {
// Create a state machine to manage transition logic
const items = createItemsStore(async () => fetch(`/items.json`).then((r) => r.json()));
// Tell the machine to initialize. Under the covers it uses the above `fetch` callback.
items.send('initialize');
return {
props: { items } // XState actors are Svelte stores
};
}
</script>
<script>
export let items;
import Items from '$components/Items.svelte';
</script>
<Items {items} /> State machineWhen an item is selected, spawn a new machine and store it in the context. // _itemsMachine.js
//…
on: {
select: {
target: '.selected',
actions: [
'selectItem',
'initializeSelectedItem'
]
}
}
//…
actions: {
selectItem: assign({
selected: (context, event) => {
return spawn(itemMachine, `item-${event.item.name}`);
}
})
} Parent componentDerive the selected item actor/store from the parent’s context. (See <!-- $components/Items.svelte -->
<script>
export let items; // XState actor/Svelte store
import { derived } from 'svelte/store';
// Derive the spawned child actor/store from the parent actor’s context
const selected = derived(items, ($items) => $items.context.selected);
import Item from '$components/Item.svelte';
</script>
<h1>Items</h1>
{#if $items.matches('initialized')}
<pre>/items</pre>
<!-- <pre>{JSON.stringify($items.context.items, null, 2)}</pre> -->
<ul>
{#each $items.context.items as item, i}
<li>
<a
href="/items/{item.name}"
on:click|preventDefault={(event) => {
items.send('select', { item });
$selected.send('initialize', item);
}}>{item.name}</a
>
</li>
{/each}
</ul>
{/if}
{#if $items.matches('initialized.selection.selected')}
<!-- Pass the actor/store as a param to the child component -->
<Item item={$selected} />
{/if} Child component<!-- $components/Item.svelte -->
<script>
export let item; // XState actor/Svelte store
</script>
<h2>Item</h2>
<pre>{JSON.stringify($item.context, null, 2)}</pre>
<label for="name">Name</label> <input id="name" name="name" value={$item.context.item.name} /> |
Beta Was this translation helpful? Give feedback.
Apparently my error was between the chair and the keyboard.
After some fiddling, here’s a summary of how I successfully wired everything up. The key insight was that XState actors (e.g. interpreted machines) are also Svelte stores. Passing stores between components allows you to let XState handle the relationships between the backing state, for example,
spawn
ing child machines. As @Rich-Harris’s comment above indicates, it’s possible to hydrate server-generated content with “real” objects, not just JSON-serializable data. 🤯The use case here is a classic collection-detail. Initially you get a list of available items. Selecting one shows its detail and allows the user to edit.
This is most…