statelyai / docs

Stately docs for Stately Studio and XState
https://stately.ai/docs
19 stars 58 forks source link

Add persisted snapshot examples #423

Open davidkpiano opened 1 week ago

davidkpiano commented 1 week ago

https://discord.com/channels/795785288994652170/1186344618116263976/1251885762836697139

namigongyi commented 1 week ago

appMachine.ts

import {
  setup,
  sendTo,
  assign,
  ActorRefFrom,
} from "xstate";
import { orderMachine } from "./orderMachine";
import { notifierMachine } from "./notifierMachine";
import { loggerMachine } from "./loggerMachine";
const makeId = () => Math.random().toString(36).slice(2);

export const appMachine = setup({
  types: {} as {
    context: {
      orders: ActorRefFrom<typeof orderMachine>[];
      quotes: any[];
    };
  },
  actors: {
    notifierMachine: notifierMachine,
    loggerMachine: loggerMachine,
  },
}).createMachine({
  id: "app",
  context: {
    orders: [],
    quotes: [],
  },
  invoke: [
    {
      src: "notifierMachine",
      systemId: "notifier",
    },
    {
      src: "loggerMachine",
      systemId: "logger",
    },
  ],
  on: {
    createOrder: {
      actions: assign({
        orders: ({ context, event, spawn }) => {
          const newOrderId = "order" + context.orders.length;
          const newOrderActor = spawn(orderMachine, {
            id: makeId(),
            input: { orderId: newOrderId },
          });

          return context.orders.concat(newOrderActor);
        },
      }),
    },
    log: {
      actions: sendTo(({ system }) => system.get("logger"), {
        type: "LOG",
        message: "Order created",
      }),
    },
  },
});

index.tsx

const App = ()=>{
   const appMachineRef = useActorRef(appMachine, {
    snapshot: JSON.parse(localStorage.getItem("app") || "null"),
  });
  const orders = useSelector(appMachineRef, (i) => i.context.orders);

  useEffect(() => {
    const subscription = appMachineRef.subscribe((snapshot) => {
      localStorage.setItem(
        "app",
        JSON.stringify(appMachineRef.getPersistedSnapshot()) // "An inline child actor cannot be persisted"
      );
    });
    return subscription.unsubscribe;
  }, [appMachineRef]);

return (
    <button onClick={() => appMachineRef.send({ type: "createOrder"})}> Click to Create Order </button>
 )
}

I want appMachine to persist the machine when appMachineRef changes . But it seems doesn't work, because of the error message "An inline child actor cannot be persisted" . is there a another way model it ?