statelyai / xstate

Actor-based state management & orchestration for complex app logic.
https://stately.ai/docs
MIT License
27.18k stars 1.26k forks source link

Bug: xstate v5/React useActor/useActorRef not restarting parent machine and spawned children after restore #4148

Closed murrowblue22 closed 1 year ago

murrowblue22 commented 1 year ago

Description

const [state, send, pam_service] = useActor(parentAppMachine, { state: restoredState })

When i use the above code to restore a machine after using the below code, to persist the machine state to localStorage. The restored machine does not got to a running state. Meaning if i send an event to the machine nothing happens no error nothing, also spawned machine actors that were running on the parent at the time the parent machine state was persisted are not restarted.

const modelMachineActorRef = useActorRef(machine) const initialPersistedState = modelMachineActorRef.getPersistedState!() localStorage.setItem('pam_service_state', JSON.stringify(initialPersistedState))

The documentation if i am reading it correctly says xstate v5 would provide this functionality In XState v5 beta, actors are now deeply (recursively) persisted. Invoked/spawned actors will be persisted, as well as actors invoked/spawned from those actors, and so on.

In the following example, the state of the mainActor will be persisted, as well as the state of the invoked someCounter actor. When the restoredActor is started, it will start at the persisted state of mainActor, which includes the persisted state of someCounter:

Expected result

i expected the parent machine and the existing spawned child actor machines to be restored to their prior state and for them to be running

Actual result

The parent machine was restored but it only showed an id value for child spawned actors

Reproduction

*

Additional context

*

davidkpiano commented 1 year ago

Can you please share a reproduction? Will reopen once that's provided.

tsxoxo commented 1 year ago

This is tangentially related at best (it's not React, the hydration happens elsewhere) but it sounds like a similar result. When I try to rehydrate from localStorage, I get 'dead actors' that don't send events back to the parent.

I've noticed that the ActorRef objects that are retrieved from storage have listener: Set(0), whereas freshly added items have 1.

Maybe this can be a piece of the thread to figure this one out.

Live code -- this is the official Todo-MVC app for Xstate + Vue, just with hydration added in todos.machine.ts:

https://codesandbox.io/p/sandbox/need-8598mq?file=%2Fsrc%2Ftodos.machine.ts%3A5%2C48

I'd love to know some ways to debug something like this -- is there a way to show all spawned actors that are 'running'?

Hope I'm not hijacking this thread too much. I'm a bit too pressed for time to open a new one right now :).

gregoralbrecht commented 1 year ago

@tsxoxo I've run into the very same problem and after looking through various docs (one, two), I found a note here:

Persisting spawned actors isn't yet supported in XState.

The new beta docs for stately.ai say this, however:

Persisting & restoring state from machine actors is deep; all invoked & spawned actors will be persisted & restored recursively.

Maybe this is added in v5? I must be looking in all the wrong places, but I can't find actor.getPersistedState() anywhere when using xstate@4.38.2 and @xstate/react@3.2.2.