@portabletext/editor
Version:
Portable Text Editor made in React
44 lines (39 loc) • 1.79 kB
text/typescript
/**
* Copy/pasted from https://github.com/statelyai/xstate/blob/main/packages/xstate-react/src/stopRootWithRehydration.ts
* and renamed to `stopActor`
*/
import type {AnyActorRef, Snapshot} from 'xstate'
const forEachActor = (
actorRef: AnyActorRef,
callback: (ref: AnyActorRef) => void,
) => {
callback(actorRef)
const children = actorRef.getSnapshot().children
if (children) {
Object.values(children).forEach((child) => {
forEachActor(child as AnyActorRef, callback)
})
}
}
export function stopActor(actorRef: AnyActorRef) {
// persist snapshot here in a custom way allows us to persist inline actors and to preserve actor references
// we do it to avoid setState in useEffect when the effect gets "reconnected"
// this currently only happens in Strict Effects but it simulates the Offscreen aka Activity API
// it also just allows us to end up with a somewhat more predictable behavior for the users
const persistedSnapshots: Array<[AnyActorRef, Snapshot<unknown>]> = []
forEachActor(actorRef, (ref) => {
persistedSnapshots.push([ref, ref.getSnapshot()])
// muting observers allow us to avoid `useSelector` from being notified about the stopped snapshot
// React reconnects its subscribers (from the useSyncExternalStore) on its own
// and userland subscibers should basically always do the same anyway
// as each subscription should have its own cleanup logic and that should be called each such reconnect
;(ref as any).observers = new Set()
})
const systemSnapshot = actorRef.system.getSnapshot?.()
actorRef.stop()
;(actorRef.system as any)._snapshot = systemSnapshot
persistedSnapshots.forEach(([ref, snapshot]) => {
;(ref as any)._processingStatus = 0
;(ref as any)._snapshot = snapshot
})
}