Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

XState helper for using asynchronous guards.

License

NotificationsYou must be signed in to change notification settings

rlaffers/xstate-async-guards

Repository files navigation

This is a helper for using asynchronous guards inXState state machines with ease.

npm versioncode style: prettierPRs Welcome

Rationale

Out of the box, XState supports only synchronous, pure condition functions (a.k.a. guards) inguarded transitions. This makes sense since synchronous transitions undertaken right after an event is received by a state machine are easy to conceptualize.

What if a guard needs external data from some asynchronous API (fetch, IndexedDB, etc.)? What if the guard execution is CPU intensive and you wish to offload it to a Web Worker? XState wants you to perform all async jobs in invoked services (or in spawned actors) which boils down to transitioning to some helper states first. That generates some boilerplate and may obscur your intentions. The problem is exacerbated when there are multiple async guard cases which need to be evaluated sequentially in a waterfall fashion.

Thexstate-async-guards library provides awithAsyncGuards helper to abstract asynchronously guarded transitions like so:

// within a state machine declarationstates:{Idle:withAsyncGuards({on:{EVENT:{cond:async(_,event)=>event.value==='start',// async function!target:'#root.Started'}}}),Started:{}}

Installation

$ npm install xstate-async-guards --save

Example

Simply wrap the state node with asynchronous guard functions in awithAsyncGuards call:

import{withAsyncGuards}from'xstate-async-guards'constmachine=createMachine({id:'root',context:{},// must not be undefinedinitial:'Idle',states:{// this state uses async guardsIdle:withAsyncGuards({on:{EVENT:[{cond:isValueStart,// async function referencetarget:'#root.Started',// must use absolute targets},{cond:'isValueFaulty',// string reference to an async function in configured guardstarget:'#root.Broken',actions:send('BROKEN'),// actions are supported},{target:'#root.Off',// default transition is optional},],// rejected guard promises can be handled explicitly'error.async-guard.isValueStart':{actions:(_,event)=>console.log('Async guard error!',event),},},id:'idle',// state ID is mandatory// all standard state props are supported. E.g.:entry:()=>console.log('entered Idle'),exit:()=>console.log('exited Idle'),invoke:{/*...*/},// etc.}),Started:{},Broken:{},Off:{},},})

See CodeSandbox here.

Options

FunctionwithAsyncGuards accepts an object as the second argument which may contain the following options:

  • inGuardEvaluation - an object withleading andtrailing boolean props.
    • leading (boolean) - When true (default),in guards will be evaluated first, before async guards are evaluated. An async guard will be evaluated only if thein guard is satisfied.
    • trailing (boolean) - When true, in guards will be evaluated after async guards have been successfully resolved. If anin guard is not satisfied at this moment, the transition will not be taken (even though the async guard is satisfied). Defaults tofalse.

Caution

A thorough consideration should be given to consequences of using asynchronous guards for conditional transitions. Importantly, by the time an async guard resolves, the world may be in a state different from where it was at the time the event triggering the transition was received. Special care should be taken if your state machine uses parallel states or globally defined transitions.

TODO

  • Support combining sync and async guards within the same state node
  • Relax the requirement for absolute targets
  • Document error handling

About

XState helper for using asynchronous guards.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp