You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Syncing external data into xstate-tree machines is something we do a lot of at Koordinates. Most commonly Observables representing selectors from redux or watched GraphQL queries, to bring global state into the machines. But we have some areas where we need to sync data from React land back into the machine at the top of the xstate-tree hierarchy. That has been implented fairly poorly with a combination of useMemo and withContext building a new root machine anytime the useMemo dependencies change.
These are a very similar class of problems however, getting data from the outside world into the xstate machines context, with different implementations but the same mental model from inside the machine. Both ways can work with some sort of sync event sent to the machine whenever the external data changes allowing you to write a single sync event action to update context. They would need different events however as the view syncing and the observable syncing wouldn't know about each other.
Syncing from view
Handwavey thought to add a new type declaration declaring viewInputs or some such. That could then be tied into the event for syncing from the view, props on the component build by buildRootComponent, and as an argument to the slot creator functions to require passing props to a slot in the view.
From there it's a useEffect away from sending an event to the machine every time the props change to allow syncing the data into context.
import{UsesFoo}from"./SomeOtherChildMachine";typeViewEvent<T>={type: "xstate-tree.viewSync";data: T};typeViewProps={foo: string};typeEvents=ViewEvent<ViewProps>;// specify props view generic of the slot factoriesconstslots=[singleSlot<ExtractViewProp<typeofUsesFoo>("UsesFoo")];constmachine=createMachine({id: "example1",schema: {events: {}asEvents,viewProps: {}asViewProps.},on: {"xstate-tree.viewSync": {actions: immerAssign((ctx,e)=>{ctx.foo=e.data.foo;})}}})// snip// foo prop in view passed in from above root component or machineconstview=buildView(...,({ slots, foo })=>{// And then this slot was typed as also taking a foo so it gets passed herereturn<slots.UsesFoofoo={foo}/>;});
This seems like it would require some sort of wrapper around a group of observables to emit a new value any time any of the observables changes, including the last emit from any other observables to ease writing the sync action handler (or would that be bad because you have no way of telling if an observable had emitted a new value 🤔).
You would then need to invoke that wrapped observable in your machine and attach a sync event action to update context when it emits.
As much as I would like automatically inject the invocation of the observable to reduce boilerplate I don't think it's advisable as it won't show up in the xstate visualizer. The reason we have been rolling back any machine config generation helpers we have at Koordinates, breaks the visualizer as the source of truth.
// Basically just combineLatest from RxJS and mapping them to an eventconstwrappedObservables$=wrapThemUp({foo: foo$,bar: bar$});typeObservableSyncEvent<T>={type: "xstate-tree.sync";data: T};typeEvents=ObservableSyncEvent<ATypeExtractor<typeofwrappedObservables$>>;constmachine=createMachine({id: "example1",schema: {events: {}asEvents,},invoke: {src: wrappedObservables$},on: {"xstate-tree.sync": {actions: immerAssign((ctx,e)=>{ctx.foo=e.data.foo;ctx.bar=e.data.bar;})}}}))
The text was updated successfully, but these errors were encountered:
I would very much love to have the syncing happen automatically (by effectively going const newContext = { ...ctx, ...syncEvent } and then opting into manual control when you needed to change that behaviour or respond to the sync event in different states. But that goes against the whole "viz is source of truth" concept
Syncing external data into xstate-tree machines is something we do a lot of at Koordinates. Most commonly Observables representing selectors from redux or watched GraphQL queries, to bring global state into the machines. But we have some areas where we need to sync data from React land back into the machine at the top of the xstate-tree hierarchy. That has been implented fairly poorly with a combination of
useMemo
andwithContext
building a new root machine anytime theuseMemo
dependencies change.These are a very similar class of problems however, getting data from the outside world into the xstate machines context, with different implementations but the same mental model from inside the machine. Both ways can work with some sort of sync event sent to the machine whenever the external data changes allowing you to write a single sync event action to update context. They would need different events however as the view syncing and the observable syncing wouldn't know about each other.
Syncing from view
Handwavey thought to add a new type declaration declaring
viewInputs
or some such. That could then be tied into the event for syncing from the view, props on the component build bybuildRootComponent
, and as an argument to the slot creator functions to require passing props to a slot in the view.From there it's a
useEffect
away from sending an event to the machine every time the props change to allow syncing the data into context.and with a root component
Syncing from obervables
This seems like it would require some sort of wrapper around a group of observables to emit a new value any time any of the observables changes, including the last emit from any other observables to ease writing the sync action handler (or would that be bad because you have no way of telling if an observable had emitted a new value 🤔).
You would then need to invoke that wrapped observable in your machine and attach a sync event action to update context when it emits.
As much as I would like automatically inject the invocation of the observable to reduce boilerplate I don't think it's advisable as it won't show up in the xstate visualizer. The reason we have been rolling back any machine config generation helpers we have at Koordinates, breaks the visualizer as the source of truth.
The text was updated successfully, but these errors were encountered: