Feature request
Would be neat if cond could accept array of guards, without this I have to make multiple transient states when my logic is more complex.
It's not a breaking change and the API would be something like this:
'': [
{ target: 'foo', cond: ['isOnline', 'hasForm'] }
]
This seems like it would work well with custom guards 馃摌 - the tricky thing with "just allowing arrays" is that it's ambiguous whether it means isOnline && hasForm or isOnline || hasForm. But you can easily do this:
const every = (...guards) => ({
type: 'every',
guards
});
const guards = {
isOnline: ctx => ctx.status === 'online',
hasForm: ctx => ctx.user.hasForm === true
};
// ...
'': [
{
target: 'foo',
cond: every('isOnline', 'hasForm')
// => { type: 'every', guards: ['isOnline', 'hasForm'] }
}
]
// ...
// machine options
{
guards: {
...guards,
every: (ctx, event, { guard }) => {
const { guards } = guard;
return guards.every(guardKey => guards[guardKey](ctx, event));
}
}
}
What do you think about that for a solution? Much more flexible than having XState be opinionated (and potentially too magical/black-box like) about custom guards.
I don't have much problem with the proposed solution, I've tackled the problem at hand in a similar fashion at the moment. My reasoning behind requesting this was that basically OR might be already represented by:
'': [ { target: 'foo', guard: 'a' }, { target: 'foo', guard: 'b' } ]
and that custom guards are harder to serialize.
I'll consider it. Good to look at prior art too: https://states-language.net/spec.html#choice-state
This feature would be really nice. An array of two strings (e.g. cond: ['isOnline', 'hasForm']) would be much easier to read and write than custom guards are.
I think an array would work as an assumed && since the || alternative can already be implemented using an array of transitions (as @Andarist mentioned) and the pattern already exists with the actions arrays (i.e. every function in the array is fired).
馃
Good point. I'll implement it - it's on the roadmap.
Good point. I'll implement it - it's on the roadmap.
Thank you!
Good point. I'll implement it - it's on the roadmap.
Any chance this would also show up for the choose action?
choose([{ cond: ['cond1', 'cond2'] }, ... ])
@cybervaldez That will most likely look like:
choose([
{ cond: and('cond1', 'cond2') }
])
Or something similar.
But you can easily do this
If anyone stumbles across this workaround, I had to make a few changes to the every guard to make it work:
- every: (ctx, event, { guard }) => {
- const { guards } = guard;
- return guards.every(guardKey => guards[guardKey](ctx, event));
}
+ every: (ctx, event, { cond }) => {
+ const { keys } = cond;
+ return keys.every(guardKey => guards[guardKey](ctx, event));
}
Most helpful comment
Good point. I'll implement it - it's on the roadmap.