xstate icon indicating copy to clipboard operation
xstate copied to clipboard

Initial value as function

Open danielbrodin opened this issue 3 years ago • 7 comments

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.

danielbrodin avatar Jun 02 '22 11:06 danielbrodin

🦋 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

changeset-bot[bot] avatar Jun 02 '22 11:06 changeset-bot[bot]

👇 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

    Try it now!

Review these changes using an interactive CodeSee Map

Legend

CodeSee Map Legend

ghost avatar Jun 02 '22 11:06 ghost

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

codesandbox-ci[bot] avatar Jun 02 '22 11:06 codesandbox-ci[bot]

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)

Andarist avatar Jun 02 '22 15:06 Andarist

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)

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.

davidkpiano avatar Jun 02 '22 23:06 davidkpiano

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

danielbrodin avatar Jun 03 '22 07:06 danielbrodin

I've created an internal ticket for v5 to work on this.

Andarist avatar Jun 06 '22 10:06 Andarist