Our 1st step will be to create a machine. It will have 3 states; state1, state2 & state3. It will also have 3 events; button1Clicked, button2Clicked & button3Clicked. Each event will transition the machine to its corresponding state. button1Clicked will transition the machine to state1, button2Clicked to state2 & button3Clicked to state3. We will use XState's InterpreterFrom type to create the type for this machine's service. Think of a service as a machine that is running.
To make this machine accessible in any React component without the need for prop drilling, we will use React's Context API. Create a React context with an object. Add a property myService to this object. This is where we will store the running machine. We use an object here so in future, if we have more machines we want to add to the global state, we can easily just add another property.
If your using Next.JS, the component exported from the pages/_app.tsx file is persisted as the user navigates to different pages in the app. This is where we want to create our service. XState's useInterpret hook takes a machine, starts it, & returns the resulting service. A service is a static reference to the running machine which can be subscribed to. This value never changes, so it will not cause re-renders. Call MyContext's provider & pass in the service. Our machine is now running and its service can now be subscribed to within any component in our app.
Create a React component. Use React's useContext hook & pass in MyContext to get access to the global state object. Then call XState's useService hook & pass in the service from the global state object to subscribe to it. The component can now read the machine's state & send events to it.
Our component will re-render when anything changes in our machine. So for every state change, ComponentA will re-render. We can optimize this so our component will only re-render when only certain parts of the machine change.
Make a new component, ComponentB. This will be an optimized component. Instead of using the useService hook, we will use XState's useSelector hook. It takes a function that determines if the component should re-render or not. Using state.matches, we will only re-render if the state changes to or from state1. If the state changes from state2 to state3, or vice-versa, our component will not re-render.
Some of the files in the sandbox below are named different because it is not in a Next.JS environment.