Initialize a Xstate Machine with Jotai Atom in Atom Pattern

Daishi Kato
InstructorDaishi Kato
Share this video with your friends

Social Share Links

Send Tweet
Published 2 years ago
Updated 2 years ago

Sometimes adding initial values through the jotai Provider is not what you want. Provider will create a whole new store with atom values

One way to initialize a state machine inside Jotai is to turn our initial lightAtom into a function createLightAtom. This function will take an initial property that we can pass to createLightMachine when we declare the function. We will then useEffect to initialize our lightMachine.

There is a small limitation with this pattern, the machine is initialized with it's default value and then over ridden with the value we pass in the effect. The initial render will use that default value while the second render will have the value we passed in.

Daishi Kato: [0:01] Our small app with Jotai and XState consists of lightMachine, lightAtom, and Light component. Using atomWithMachine from the Jotai XState integration, we can initialize a machine using some other atom values.

[0:17] The initialLightAtom is to keep the initial light value in the machine. To set a value of the initialLightAtom, we can use Provider. However, in some cases, using Provider is not a good option because Provider will create a whole new store for all atom values. While we have various options, including keeping using Provider, we will explore a pattern to initialize the machine in a component.

[0:47] Let's modify our code. Instead of creating lightAtom globally, we convert it to a function, createLightAtom, to create a new atomWithMachine. This function takes an argument, initial. We then create an atom called lightAtomAtom.

[1:11] This naming convention tells that this atom holds lightAtom config object as its value. We put createLightAtom result as a default value of lightAtomAtom. This pattern is called atom in atom and it can be used without XState.

[1:33] Let's move on to the Light component. This component now receives a prop, initial, when we first use lightAtomAtom. It returns lightAtom and setLightAtom. We then add useEffect to call setLightAtom with a newly created machine atom.

[1:53] Notice, we pass initial to the useEffect dependency list. A new machine is created whenever the initial prop changes. The rest of the code in the Light component is unchanged. Finally, instead of using initial various prop in the Provider component, we pass the initial prop to the Light component.

[2:19] Let's see how it behaves. It shows circles with specified initial colors. Clicking circles works fine too. There is a small limitation in this usage. We are changing lightAtomAtom in the effect. This means the first render comes with the default machine, which has green for the initial value.

[2:45] In the second render, the new machine is used, so we see flickering of the first render.

[2:52] There are some ways to solve this limitation, but it depends on requirements, and we don't go into detail in this lesson. What we learn in this lesson is that we can delay initializing the machine atom with admin atom pattern.

[3:09] The lightAtomAtom holds lightAtom as its value. We use the useAtom hook twice in the Light component. The benefit of this pattern is that we can change the initial prop in the Light component. When it changes, a new machine is created.

Gush
Gush
~ 10 months ago

Great - but it could use going into more details! for instance the ways it is possible to overcome the useEffect issue in the last lesson or more common uses. Overall great work, thanks!

Markdown supported.
Become a member to join the discussionEnroll Today