State machine advent: Accessing private actor state in components (23/24)
Tags: typescript, javascript, react
Published: 2019-12-23 22:55:41

[Yesterday](https://dev.to/codingdive/state-machine-advent-building-hierarchy-using-the-actor-model-and-cross-machine-communication-2ln1), we saw how to use the actor model to create hierarchy in applications and how to treat every actor as a computational unit that encapsulates behavior. Further, we established how actors have private state that can only be accessed from other actors using explicit communication (events). To build user interfaces, however, we do oftentimes want to access the private state of actors and render them to our UI. Today, we want to build a React component that renders the `context` of the `Player` actor.

Oftentimes, we can just mimic our actor architecture with React components. As a result, we can have a `Game` component that invokes the `gameMachine` and renders a `Player` component to display the action (Rock, Paper, Scissors) the player performed. Meanwhile, the `gameMachine` is a parent itself because it invokes the `player` actor. Essentially, recreating the same hierarchy and relationships between components that we first defined within our machines.

We can iterate through the array that holds the references to the player actor and pass them to the child component as props which can then deal with them in two different ways as we'll see in a minute. 


```tsx
import { useMachine } from '@xstate/react';
import React, { Fragment } from 'react';
import { Player } from './Player';

const Game = () => {
  const [state, send] = useMachine(gameMachine)

  return (
    <div>
      {state.context.playerRefs.map((playerRef, index) => (
        <Fragment key={index}>
          <Player playerRef={playerRef} />
        </Fragment>
      ))}
    </div>
  )
}
```

Once we define the `Player` component, we have a decision to make. Do we only want to access the actor so that we can receive and send events to it or do we want to access its private state? Although not the goal for today, for the former option, we should go with the `useActor` hook from the `@xstate/react` package. 

When using this hook, `state` does not hold the context property since the actor state is private. Nonetheless, we could use the actor to send events from within our component.

```tsx
import { useActor } from '@xstate/react';
import { PlayerActor } from './actorMachine'

const Player = ({playerRef}: {playerRef: PlayerActor }) => {
  const [state, send] = useActor(playerRef);
  // state.context === undefined 
  return null;
}
```

On the other hand, if we do want to access the context, we could make use of the running service which is another word for an invoked machine by using the `useService` hook of the same package.

```tsx
import { useService } from '@xstate/react';
import { PlayerService } from './actorMachine'

const Player = ({playerRef}: {playerRef: PlayerService }) => {
  const [state, send] = useService(playerRef);

  return (
    <p>{state.context.identity} decided on: {state.context.playedAction}</p>
  );
}
```

Passing the reference to the actor into the `useService` subscribes the component to all the state changes of the actor. As a result, when the context or finite-state of the player actor changes, the component is rerendered as well. Needless to say, the reactive nature of state machines and React work harmoniously well together.

For a complete example, check the [codesandbox](https://codesandbox.io/s/ecstatic-leavitt-9codx) for today's lecture and pay special attention to the type differences of the two respective hooks as pointed above (`PlayerActor` vs `PlayerService`).

### 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.