Xstate: Allow State.matches() to match multiple states

Created on 9 Jan 2020  路  6Comments  路  Source: davidkpiano/xstate

Bug or feature request?

Feature request / query

Description:

I have a piece of UI that I'd like to display when one of multiple states is true. At the moment, I'm writing code like this:

const displayCustomerBalance = current.matches("customer_deposit") || current.matches("customer_withdrawal");

This is okay, but gets a bit cumbersome when you add more states. It would be nice to be able to write something more like:

const displayCustomerBalance = current.matches([
  "customer_deposit",
  "customer_withdrawal"
]);

It might be that you can actually do something like this and I've missed or misunderstood something. If so, sorry!

(Feature) Potential implementation:

I think adding an overload for State.matches() with a signature like this would work, where TSV is a union of the possible value types instead of a single value type:

matches<TSV>(parentStateValues: TSV[]): this is TState extends { value: TSV; } ? State<TState["context"], TEvent, TStateSchema, TState> : never

It would call utils.ts/matchesState for each of the state values passed in, and return true if any of them were true.

documentation

Most helpful comment

const isMatch = ["customer_deposit", "customer_withdrawal"].some(current.matches)

Would that work?

All 6 comments

This can be easily added in userland as a custom helper, not sure if it's worth overloading a core feature with this complexity.

That's fair enough. My main argument in favour of the change would be that, because it's such a core feature, it makes sense to prioritise ergonomics. The pattern of providing either a single value or an array exists elsewhere in the library (when defining actions on a state transition, for example), so I assumed it would work on matches() and was surprised when it didn't.

As an aside, the array form doesn't currently produce a TypeScript error or throw an exception, it just returns false. Are there cases when a state value can actually be an array, or is this a bug?

Are there cases when a state value can actually be an array, or is this a bug?

There are not - it's always object and/or string.

I'll add this as an enhancement to V5, which will be much more modular, so adding this helper will not be included in the bundle.

Sounds good to me!

const isMatch = ["customer_deposit", "customer_withdrawal"].some(current.matches)

Would that work?

I have made the following helper function that seems to work well.

export const matchesMachineState = (
  states: string[],
  machine: State<any, any, any, any>
) => (states.find((state) => machine.matches(state)) ? true : false);
Was this page helpful?
0 / 5 - 0 ratings

Related issues

bradwoods picture bradwoods  路  3Comments

carloslfu picture carloslfu  路  3Comments

dakom picture dakom  路  3Comments

hnordt picture hnordt  路  3Comments

greggman picture greggman  路  3Comments