DEV Community

Discussion on: "Just Use Props": An opinionated guide to React and XState

Collapse
 
redbar0n profile image
Magne • Edited

Couldn't you just use the same machine in both the parent and the child component? Since state machines are orthogonal to the component (rendering) hierarchy then they don't have to conform to it. (Presuming here that the useMachine hook will cause a re-render, of course.)

Like this:

import { useMachine } from '@xstate/react';
import { createMachine } from 'xstate';

/**
 * Types for the machine declaration
 */
type MachineContext = {};
type MachineEvent = { type: 'TOGGLE' };

const machine = createMachine<MachineContext, MachineEvent>({});

const ParentComponent = () => {
  const [state, send] = useMachine(machine);
  // ... some extra code that warrants using this macine in this component ...
  return (
    <ChildComponent />
  );
};

const ChildComponent = () => {
  const [state, send] = useMachine(machine);
  return (
    <button onClick={() => send('TOGGLE')}>
      {state.matches('open') ? 'Open' : 'Closed'}
    </button>
  );
};
Enter fullscreen mode Exit fullscreen mode

Thus, state could be stored in the relevant component, but accessed from any other component (not just a child), without having to conform to passing props up and down the render tree. You'd also be utilising the full capacity of hooks:

Hooks allow you to reuse stateful logic without changing your component hierarchy. This makes it easy to share Hooks among many components or with the community.

reactjs.org/docs/hooks-intro.html

Collapse
 
mattpocockuk profile image
Matt Pocock

No - state is not shared between the two machines.

This is like calling useReducer twice, using the same reducer.

Collapse
 
redbar0n profile image
Magne • Edited

Ah, ok, I see that useMachine actually creates a new service...

Is there another way of having the state independent of the React tree (so one does not even have to pass props)? (While also having React re-render the components where the state is used when it changes).

Maybe putting the const [state, send] = useMachine(machine); into a shared hook that is used inside the relevant components?

Or extract that line outside of any component and then referencing state and send inside components (as a closure)?

Thread Thread
 
redbar0n profile image
Magne

Seems like using React's Context is the recommended approach: github.com/statelyai/xstate/discus...

Thread Thread
 
redbar0n profile image
Magne

This is the closest to what I was originally thinking: github.com/statelyai/xstate/discus...