Skip to main content
Module

x/jotai/docs/integrations/xstate.mdx

👻 Primitive and flexible state management for React
Go to Latest
File
---title: XStatedescription: This doc describes XState integration.nav: 4.04---
Jotai's state management is primitive and flexible,but that sometimes means too free.XState is a sophisticated library to providea better and safer abstraction for state management.
## Install
You have to install `xstate` and `jotai-xstate` to use this feature.
```npm install xstate jotai-xstate# oryarn add xstate jotai-xstate```
## atomWithMachine
`atomWithMachine` creates a new atom with XState machine.It receives a function `getMachine` to create a new machine.`getMachine` is invoked at the first use with `get` argument,with which you can read other atom values.
```tsximport { useAtom } from 'jotai'import { atomWithMachine } from 'jotai-xstate'import { assign, createMachine } from 'xstate'
const createEditableMachine = (value: string) => createMachine<{ value: string }>({ id: 'editable', initial: 'reading', context: { value, }, states: { reading: { on: { dblclick: 'editing', }, }, editing: { on: { cancel: 'reading', commit: { target: 'reading', actions: assign({ value: (_, { value }) => value, }), }, }, }, }, })const defaultTextAtom = atom('edit me')const editableMachineAtom = atomWithMachine((get) => // `get` is available only for initializing a machine createEditableMachine(get(defaultTextAtom)))
const Toggle = () => { const [state, send] = useAtom(editableMachineAtom) return ( <div> {state.matches('reading') && ( <strong onDoubleClick={send}>{state.context.value}</strong> )} {state.matches('editing') && ( <input autoFocus defaultValue={state.context.value} onBlur={(e) => send({ type: 'commit', value: e.target.value })} onKeyDown={(e) => { if (e.key === 'Enter') { send({ type: 'commit', value: e.target.value }) } if (e.key === 'Escape') { send('cancel') } }} /> )} <br /> <br /> <div> Double-click to edit. Blur the input or press <code>enter</code> to commit. Press <code>esc</code> to cancel. </div> </div> )}```
## Restartable machine stored in a global Provider (provider-less mode)
When your machine reaches its final state it cannot receive any more events.If your atomWithMachine is initialized in global scope (aka provider-less mode),to restart it you need to send a `RESTART` event to your machine like so:
```tsximport { RESTART } from 'jotai-xstate'
const YourComponent = () => { const [current, send] = useAtom(yourMachineAtom) const isFinalState = current.matches('myFinalState') useEffect(() => { // restart globally initialized machine on component unmount return () => { if (isFinalState) send(RESTART) } }, [isFinalState])}```
## Examples
Check examples with atomWithMachine:
<CodeSandbox id="fxtoe3" />Restartable machine:
<CodeSandbox id="n179xd" />## Tutorials
Check out a course about Jotai and XState.
[Complex State Management in React with Jotai and XState](https://egghead.io/courses/complex-state-management-in-react-with-jotai-and-xstate-3be0a740)
(Note: In the course, it uses `jotai/xstate` which is supersede by `jotai-xstate`.)