Last active
December 3, 2020 08:41
-
-
Save ilumin/97b7b9f52aed865322c6cb79f44bc6a6 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
defined: actions in config | |
note: | |
- states: contain state of machine | |
- on: contain event support on state | |
- event can define as string of state name or an object of target state and action | |
- action can do side effect | |
# Mutate context by assign | |
*/ | |
const config = { | |
id: 'lightBulb', | |
initial: 'unlit', | |
context: { | |
color: '#FFF', | |
}, | |
states: { | |
lit: { | |
on: { | |
BREAK: 'broken', | |
TOGGLE: 'unlit', | |
CHANGE_COLOR: { | |
actions: ['changeColor'] | |
} | |
}, | |
exit: ['logChange'], | |
}, | |
unlit: { | |
on: { | |
BREAK: 'broken', | |
TOGGLE: 'lit', | |
}, | |
exit: ['logChange'], | |
}, | |
broken: { | |
entry: ['logBroken'] | |
}, | |
} | |
} | |
const options = { | |
actions: { | |
logBroken: (ctx, evt) => console.log(`I'm broke at ${evt.location || `somewhere`}.`), | |
logChange: (ctx, evt) => console.log(`changed: `, ctx, evt), | |
changeColor: assign((ctx, evt) => ({ color: evt.color || 'no-color-here' })) | |
} | |
} | |
const lightBulbMachine = Machine( | |
config, | |
options | |
); | |
/** | |
* Hierarchical state can transfer to extenal state by using id of state | |
*/ | |
const doorMachine = Machine( | |
{ | |
id: 'door', | |
initial: 'locked', | |
states: { | |
locked: { | |
id: 'locked', | |
on: { | |
UNLOCK: 'unlocked', | |
} | |
}, | |
unlocked: { | |
initial: 'closed', | |
states: { | |
closed: { | |
on: { | |
LOCK: '#locked', | |
OPEN: 'opened' | |
} | |
}, | |
opened: { | |
on: { | |
CLOSE: 'closed' | |
} | |
} | |
} | |
}, | |
} | |
} | |
) | |
/** | |
* XState support parallel state transition | |
*/ | |
const spaceHeaterMachine = Machine( | |
{ | |
id: 'spaceHeater', | |
initial: 'powerOff', | |
states: { | |
powerOff: { | |
on: { TOGGLE: 'powerOn.hist' } | |
}, | |
powerOn: { | |
on: { TOGGLE: 'powerOff' }, | |
type: 'parallel', | |
states: { | |
heated: { | |
initial: 'lowHeat', | |
states: { | |
lowHeat: { | |
on: { TOGGLE_HEAT: 'highHeat' } | |
}, | |
highHeat: { | |
on: { TOGGLE_HEAT: 'lowHeat' } | |
} | |
} | |
}, | |
ascillation: { | |
initial: 'disabled', | |
states: { | |
disabled: { | |
on: { TOGGLE_OSC: 'enabled' } | |
}, | |
enabled: { | |
on: { TOGGLE_OSC: 'disabled' } | |
}, | |
} | |
}, | |
hist: { | |
type: 'history', | |
history: 'deep', | |
} | |
} | |
}, | |
} | |
} | |
); | |
const tryMachine = Machine( | |
{ | |
id: 'tryMachine', | |
context: { | |
tries: 0 | |
}, | |
initial: 'idle', | |
states: { | |
idle: { | |
on: { TRYING: 'trying' } | |
}, | |
trying: { | |
entry: ['incTries'], | |
on: { | |
'': [ | |
{ target: 'success', cond: 'triedEnough' }, | |
{ target: 'idle' } | |
] | |
} | |
}, | |
success: {} | |
} | |
}, | |
{ | |
actions: { | |
incTries: assign({ | |
tries: ctx => ctx.tries + 1 | |
}) | |
}, | |
guards: { | |
triedEnough: ctx => ctx.tries > 2 | |
} | |
} | |
) | |
/** | |
* Example use case traffic light | |
* 1. traffice light should run automatically with delayed time | |
* 2. delay time can defined as `delays` in options and defined with `after` | |
* 3. example of machine event | |
* 3.1 machine event can trigger target state | |
* 3.2 trigger to previous state | |
* 3.3 add condition so that it won't trigger if not met condition | |
*/ | |
const stoplightMachine = Machine({ | |
id: 'stoplight', | |
initial: 'red', | |
context: { | |
rushHourMultiplier: 1 | |
}, | |
on: { | |
INC_RUSH_HOUR: { | |
target: '#stoplight.hist', | |
cond: 'maxModifier', | |
actions: ['incRushHour'] | |
}, | |
DEC_RUSH_HOUR: { | |
target: '#stoplight.hist', | |
cond: 'minModifier', | |
actions: ['decRushHour'] | |
} | |
}, | |
states: { | |
green: { | |
after: { | |
GREEN_TIMER: 'yellow' | |
} | |
}, | |
yellow: { | |
after: { | |
YELLOW_TIMER: 'red' | |
} | |
}, | |
red: { | |
after: { | |
RED_TIMER: 'green' | |
} | |
}, | |
hist: { | |
type: 'history' | |
} | |
}, | |
}, | |
{ | |
actions: { | |
incRushHour: assign({ | |
rushHourMultiplier: ctx => ctx.rushHourMultiplier + 1 | |
}), | |
decRushHour: assign({ | |
rushHourMultiplier: ctx => ctx.rushHourMultiplier - 1 | |
}) | |
}, | |
delays: { | |
GREEN_TIMER: ctx => ctx.rushHourMultiplier * 3000, | |
YELLOW_TIMER: ctx => ctx.rushHourMultiplier * 1000, | |
RED_TIMER: ctx => ctx.rushHourMultiplier * 4000 | |
}, | |
guards: { | |
minModifier: ctx => ctx.rushHourMultiplier > 1, | |
maxModifier: ctx => ctx.rushHourMultiplier < 5, | |
} | |
}) | |
const fetchCureAnimals = () => { | |
return fetch(`https://www.reddit.com/r/aww.json`) | |
.then(res => res.json()) | |
.then(json => json.data.children.map(child => child.data)) | |
} | |
/** | |
* invoke promise function | |
* instead of use `on` just use `invoke` | |
* and defined promise function want to trigger | |
* and defined onDone, onError to handle promise event | |
*/ | |
const cuteAnimalsMachine = Machine( | |
{ | |
id: 'cuteAnimals', | |
initial: 'idle', | |
context: { | |
cuteAnimals: null, | |
error: null, | |
}, | |
states: { | |
idle: { | |
on: { FETCH: 'loading' } | |
}, | |
loading: { | |
invoke: { | |
id: 'fetchCureAnimals', | |
src: fetchCureAnimals, | |
onDone: { | |
target: 'success', | |
actions: assign({ | |
cuteAnimals: (ctx, evt) => evt.data | |
}) | |
}, | |
onError: { | |
target: 'failure', | |
actions: assign({ | |
error: (ctx, evt) => evt.data | |
}) | |
} | |
} | |
}, | |
success: { | |
type: 'final' | |
}, | |
failure: { | |
on: { RETRY: 'loading' } | |
}, | |
} | |
} | |
) | |
/** | |
* invoke callback event | |
* by define invoke | |
* and send event to callback function | |
*/ | |
const callbackEcho = (ctx, evt) => (callback, onEvent) => onEvent(e => e.type === 'HEAR' && callback('ECHO')) | |
const listingMachine = Machine( | |
{ | |
id: 'listening', | |
initial: 'listening', | |
states: { | |
listening: { | |
invoke: { | |
id: 'callbackEcho', | |
src: callbackEcho | |
}, | |
on: { | |
SPEAK_FOO: { | |
actions: send('FOO', { | |
to: 'callbackEcho' | |
}) | |
}, | |
SPEAK_HEAR: { | |
actions: send('HEAR', { | |
to: 'callbackEcho' | |
}) | |
}, | |
ECHO: { | |
actions: () => console.log('echo, echo') | |
}, | |
} | |
} | |
} | |
} | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment