š»š¤
npm install jotai-xstateš»š¤
Jotai integration library for XState
https://jotai.org/docs/integrations/xstate
Creates an atom that creates, stores and manages an Actor, given it's logic. Follows mostly the same API as createActor.
``tsx
const promiseLogic = fromPromise(() => fetch('http://some.host/...')) // or fromTransition, fromObservable, fromEventObservable, fromCallback, createMachine
const actorAtom = atomWithActor(promiseLogic)
const Component = () => {
const [actorRef, send] = useAtom(actorAtom)
...
}
`
Can also be called with a second opts argument for setting up actor parameters. In typescript it's important to correctly type the actors Input, Output and Events. Refer to the examples for a full implementation
`tsxhttp://some.host/${input.id}
const promiseLogic = fromPromise(({ input }: { input: { id: number } }) =>
fetch(),
);
const actorAtom = atomWithActor(promiseLogic, { input: { id: 2 } });
// ^ Will type-error if you don't provide input
`
Either param can also be a Getter function, allowing you to derive data from other atoms
`tsxhttp://some.host/${input.id}
const promiseLogicAtom = atom(
fromPromise(({ input }: { input: { id: number } }) =>
fetch(),
),
);
const idAtom = atom(2);
const actorAtom = atomWithActor(
(get) => get(promiseLogicAtom),
(get) => {
return { input: { id: get(idAtom) } };
},
);
`
You can fully type all inputs, outputs and events.
`tsx
type PromiseLogicOutput = string;
type PromiseLogicInput = { duration: number };
type PromiseLogicEvents =
| { type: 'elapsed'; value: number }
| { type: 'completed' };
const promiseLogicAtom = atom(
fromPromise
async ({ emit, input }) => {
const start = Date.now();
let now = Date.now();
do {
await new Promise((res) => setTimeout(res, 200));
emit({ type: 'elapsed', value: now - start });
now = Date.now();
} while (now - start < input.duration);
emit({ type: 'completed' });
return 'Promise finished';
},
),
);
const actorAtom = atomWithActor((get) => get(promiseLogicAtom), {
input: { duration: 3000 },
});
const Component = () => {
// actorRef allows access to the return of 'createActor'
const [actorRef, send] = useAtom(actorAtom);
useEffect(() => {
const subscription = actorRef.on('elapsed', console.log);
return () => subscription.unsubscribe;
}, [actorRef]);
return ...
};
`
Important!!
By default atomWithActor will call actor.start() as soon as it mounts. To change this behaviour you can provide { autoStart: false } in your options and start it manually
`tsx
const promiseLogic = fromPromise(
() => new Promise((res) => setTimeout(res, 1000)),
); // or fromTransition, fromObservable, fromEventObservable, fromCallback, createMachine
const actorAtom = atomWithActor(promiseLogic, { autoStart: false });
const Component = () => {
const [actorRef, send] = useAtom(actorAtom);
return (
);
};
`
Provides access to an actors up-to-date snapshot while also handling it's lifecycle and listeners. Takes in an instanced actor or a getter function that returns one.
`tsx
type PromiseLogicOutput = string
// or fromTransition, fromObservable, fromEventObservable, fromCallback, createMachine
const promiseLogic = fromPromise
res => setTimeout(() => res("Return from inside logic"), 1000)
))
const actorAtom = atomWithActor(promiseLogic)
// Here get() is required because the actor logic is also stored in an atom
const actorSnapshot = atomWithActorSnapshot(get => get(actorAtom))
const Component = () => {
const [actorRef, send] = useAtom(actorAtom)
const [snapshot, clear] = useAtom(actorSnapshot)
return (
}
Calling this atom's
write function (named clear in the example above) will clear the internal snapshot and reset the listeners. This is usefull when combined with calling send(RESTART) on the actor logic, especially when it depends on derived values.`tsx
type PromiseLogicOutput = string
type PromiseLogicInput = { duration: number }
// or fromTransition, fromObservable, fromEventObservable, fromCallback, createMachine
const promiseLogic = fromPromise(({input}) => new Promise(
res => setTimeout(() => res("Return from inside logic"), input.duration)
))const durationAtom = atom(1000)
const actorAtom = atomWithActor(promiseLogic)
// Here get() is required because the actor logic is also stored in an atom
const actorSnapshot = atomWithActorSnapshot(get => get(actorAtom))
const Component = () => {
const [actorRef, send] = useAtom(actorAtom)
const [snapshot, clear] = useAtom(actorSnapshot)
const [duration, setDuration] = useAtom(durationAtom)
return (
{snapshot.state === "active" && "Waiting on timeout"}
{snapshot.state === "done" && (
Waited for {duration}ms
Actor output is: {snapshot.output}
)}
)
...
}
``https://jotai.org/docs/integrations/xstate