Derive Jotai Atom State from Complex State Managed in Xstate

Daishi Kato
InstructorDaishi Kato
Share this video with your friends

Social Share Links

Send Tweet

Sometimes you need to display values in specific ways throughout your application based on the state that you are managing. The way to do this is to derive your state so you don't have to track multiple stateful items.

In Jotai, this is accomplished by creating an atom, getting the value from another atom that you are managing (in this case from Xstate), and using that value how you need it in your derived atom. This atom will be re-evaluated every time the managed state changes.

This pattern is great to use if you have complex state managed in something like Xstate but need a derived state value that is not strongly tied to that managed state. The pattern works the same for async and synchronous function calls as well as pulling in multiple atoms and libraries to use in your derived state.

Instructor: [0:02] LightMachine is created with createMachine function from the XState library. lightAtom is created with atomWithMachine function from the jotai/xstate integration library.

[0:16] So far, we've just used the machine wrapped in the atom. This can actually be done with the React integration library from XState. The benefit of jotai/xstate integration is that we can derive machine atoms. Such derived atoms can be async atoms.

[0:40] Let's try async atoms. First, we define an async function. fetchLightMessage is an async function emulating data fetching from somewhere. It takes an argument, light. Waits for 1.5 seconds and returns a string.

[1:03] Next, we define a derived atom. Async message atom is an atom that gets light atom state value, passes it to the async function we just defined, and returns the result. Whenever the light atom changes, it will be re-evaluated.

[1:27] Finally, we define a component to show the value of async message atom. It simply displays the message string as an SVG text element.

[1:44] We need to hook it up in the light component. Because we use an async atom, which can suspend, it requires a suspense boundary. The light message component is put in it.

[2:02] For the suspense for work, there's a loader component defined below. It's an SVG element with a circle animation. We are done. Let's check how it works.

[2:19] If you click the circle, it changes the color. At the same time, the async function is started, and loader is shown. After a while, we see the updated text with the color value.

[2:34] This pattern will be useful if you have a complex state managed by XState and derived states that are not strongly tied to the base complex state. The derived state can also depend on other atoms or even atoms from other libraries.

[2:54] To demonstrate that this pattern can also work for non-suspense use case, let's change our async function to be sync. We just remove async keywords and comment out one await line.

[3:10] The suspense boundary is no longer necessary because none of atoms are async. It works as you would expect.