State machine advent: How to match against nested states in XState (10/24)
Tags: javascript, typescript, react
Published: 2019-12-10 18:23:01

In the [5th post of the series](https://dev.to/codingdive/state-machine-advent-invoking-a-state-machine-in-react-1nm7), we saw how to invoke a state machine in React. Now that we have learned about statecharts to model [nested and parallel states](https://dev.to/codingdive/state-machine-advent-introduction-to-nested-and-parallel-states-using-statecharts-7ed), we want to learn how to invoke it and determine its current state. 

As seen in the [codesandbox](https://codesandbox.io/s/beautiful-germain-hueum) for today's lecture, the code to invoke the statechart does not differ from invoking a regular state machine in XState. This is one of many reasons why XState is awesome. By abstracting both state machines and statecharts into the same machine object that is being accepted by the `useMachine` hook from the `@xstate/react` package, XState provides a really clean API surface to define and invoke machines. As a result, it removes a lot of cognitive overhead whether we are dealing with a regular state machine (Day 2 - 8) or some sophisticated statechart (Day 9).
The API stays the same:

`const [state, send] = useMachine(videoChatMachine);`

One thing that does change however is the way we assert the current state of our statechart.

Just to recap, our state structure of the `videoChatMachine` looked like this:

```typescript
interface VideoChatStateSchema {
  states: {
    audio: {
      states: {
        enabled: {};
        disabled: {};
      };
    };
    video: {
      states: {
        enabled: {};
        disabled: {};
      };
    };
  };
}
```

Due to the fact that `video` and `audio` are parallel to each other (you can't see this within the state schema as the `type` of the machine only needs to be specified in the implementation of the machine), they both must have an initial state and are stateful at all times.

As a consequence, `state.matches("audio")` will always return `true`. If we want to assert if the `audio` is `enabled` or `disabled`, we have to match against the nested state structure. Luckily, the `state.matches` API does not only accept a string value, it's an overloaded function (are you allowed to say that in JavaScript? 😁) that also accepts an object. The object should replicate our exact state structure up until the state node that we want to match against. 

`state.matches({audio: 'enabled'})`

Should your state architecture grow deeper, you can apply the same concept - of creating an object that replicates the state structure - to match deeply nested states.

```typescript
interface SampleStateSchema {
  states: {
    grandparentStateNode: {
      states: {
        parentStateNode: {
          states: {
            childStateNode: {};
            someOtherChildStateNode: {};
          };
        };
      };
    };
  };
}

// define & invoke machine ...
```

If you then want to assert that the invoked machine is inside the `childStateNode`, you can do so by passing a deeply nested object to the `matches` function.

`state.matches({ grandparentStateNode: { parentStateNode: 'childStateNode' } });`



### About this series
Throughout the first 24 days of December, I'll publish a small blog post each day teaching you about the ins and outs of state machines and statecharts.

The first couple of days will be spent on the fundamentals before we'll progress to more advanced concepts.