xstate
xstate copied to clipboard
Initial value as function
This PR makes it possible to set the initial state from a function. My use case for this is that I have a parallel machine where I want parts of it to be saved in localStorage, and then initiated with that value. There might be some better way to do this, but currently I am doing this
{
Volume: {
initial: 'Initial',
states: {
Initial: {
invoke: {
src: () =>
Promise.resolve(
localStorage.getItem('volume-state') ?? 'Unmuted'
),
onDone: [
{
cond: (c, e) => e.data === 'Muted',
target: 'Muted',
},
{ target: 'Unmuted' },
],
},
},
Muted: {
entry: () => localStorage.setItem('volume-state', 'Muted'),
on: {
Toggle: {
target: 'Unmuted',
},
},
},
Unmuted: {
entry: () => localStorage.setItem('volume-state', 'Unmuted'),
on: {
Toggle: {
target: 'Muted',
},
},
},
},
},
}
With this change I would instead be able to do this
Volume: {
initial: () => localStorage.getItem("volume-state") ?? "Unmuted",
states: {
Muted: {
entry: () => localStorage.setItem("volume-state", "Muted"),
on: {
Toggle: {
target: "Unmuted",
},
},
},
Unmuted: {
entry: () => localStorage.setItem("volume-state", "Unmuted"),
on: {
Toggle: {
target: "Muted",
},
},
},
},
},
It makes it easier and cleaner to be able to restore parts of a parallel state, but also for saving the state without having to save the complete state tree and restore it.
🦋 Changeset detected
Latest commit: 77e7ea1614e464fe26bad5ce220dd0da4856cb12
The changes in this PR will be included in the next version bump.
This PR includes changesets to release 1 package
| Name | Type |
|---|---|
| xstate | Minor |
Not sure what this means? Click here to learn what changesets are.
Click here if you're a maintainer who wants to add another changeset to this PR
👇 Click on the image for a new way to code review
-
Make big changes easier — review code in small groups of related files
-
Know where to start — see the whole change at a glance
-
Take a code tour — explore the change with an interactive tour
-
Make comments and review — all fully sync’ed with github
Legend

This pull request is automatically built and testable in CodeSandbox.
To see build info of the built libraries, click here or the icon next to each commit SHA.
Latest deployment of this branch, based on commit 77e7ea1614e464fe26bad5ce220dd0da4856cb12:
| Sandbox | Source |
|---|---|
| XState Example Template | Configuration |
| XState React Template | Configuration |
I like the idea and I wish we had support for smth like this. But I think that a better direction would be to allow using conditional transitions for initial. This could have better support for our tooling (studio, typegen, etc) as it's easier to statically analyze those. I would have to recheck but I think that this might even be already implemented on the next branch (or there is at least some groundwork laid out for it there)
I like the idea and I wish we had support for smth like this. But I think that a better direction would be to allow using conditional transitions for
initial. This could have better support for our tooling (studio, typegen, etc) as it's easier to statically analyze those. I would have to recheck but I think that this might even be already implemented on thenextbranch (or there is at least some groundwork laid out for it there)
Initial actions are, but not a conditional initial target. We could make an RFC for that idea because it's still viable, given that it is deterministic:
// IDEA
initial: [
{ guard: 'something', target: 'first' },
{ target: 'second'
]
But with the original use-case, the more straightforward way to accomplish this is by persisting and restoring all state.
the more straightforward way to accomplish this is by persisting and restoring all state.
Well not really, because we can't restore all state. All states except one has to start from scratch. Your idea however would probably solve this as well since you could have a guard with localStorage.getItem('volume-state') === 'Muted'.
I've created an internal ticket for v5 to work on this.