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
Updating the context with regular state(...) is easy, you just do it inside of transition with reduce, eg.:
ready: state(transition('togglePanel','ready',reduce(togglePanel))// update the context and stay on the same `ready` state),
Now here is my problem (or perhaps some misunderstanding) - how do I do the same thing for invoke? What if I need some other transitions to update the context while the invoke is running?
For example I have machine which loads data to display in panel, and in the machine there is state for the data and for the panel opened/closed state - and I want to be able to toggle the panel while the data is loading. Here is how I implemented it so far:
typeContext={loadAsyncData: ()=>Promise<string[]>;asyncData: string[];panelOpened: boolean;};consttogglePanel=(ctx: Context): Context1=>({
...ctx,panelOpened: !ctx.panelOpened,});constsetAsyncData=(ctx: Context,{ data }: {data: string[]}): Context=>({ ...ctx,asyncData: data});conststate={initial: state(immediate('loading')),loading: invoke(({ loadAsyncData }: Context)=>loadAsyncData(),transition('done','ready',reduce(setAsyncData)),transition('error','error'),// Here is the problem, I am using the same approach as with the first example but// it does not work, because invoke is run again and it fetches the data again. // Is there a way to run the invoke only once (and the done/error only once) at the beginning but not when running the `togglePanel`?transition('togglePanel','loading',reduce(togglePanel)),),ready: state(transition('togglePanel','ready',reduce(togglePanel))),error: state(transition('togglePanel','error',reduce(togglePanel))),};
The text was updated successfully, but these errors were encountered:
For anyone that would encounter the same problem, we managed to workaround this with introduction our own version of invoke
import{invoke,Machine,MachineState,Service,Transition}from'robot3';constinvokeFnType: {enter: (machine2: Machine,service: Service<Machine>,event?: unknown)=>Machine;// fn is inherited so it should always be definedfn?: (ctx: Machine['context'],event?: unknown)=>Promise<unknown>;}={enter(machine2: Machine,service: Service<Machine>,event?: unknown){// Only invoke the function if the machine state changedif(machine2.current!==service.machine.current){this.fn?.call(service,service.context,event).then((data: unknown)=>service.send({type: 'done', data })).catch((error: unknown)=>service.send({type: 'error', error }));}returnmachine2;},};// Only invoke the async function (and the done/error transition) when transitioning into the state from other state,// Do not invoke when transitioning from the same state (this is the only difference between invoke and this function)exportconstinvokeExceptForSelfTransitions=<C,T>(fn: (ctx: C,event?: unknown)=>Promise<T>,
...args: Transition[]): MachineState=>({
...invoke(fn, ...args),
...invokeFnType,});
Updating the context with regular
state(...)
is easy, you just do it inside oftransition
withreduce
, eg.:Now here is my problem (or perhaps some misunderstanding) - how do I do the same thing for invoke? What if I need some other transitions to update the context while the invoke is running?
For example I have machine which loads data to display in panel, and in the machine there is state for the data and for the panel opened/closed state - and I want to be able to toggle the panel while the data is loading. Here is how I implemented it so far:
The text was updated successfully, but these errors were encountered: