1

I am trying to create a state machine which can persist the machine's state details at any given point in time and then restore the machine with the persisted state and context values on revisiting the page. The Xstate docs mention about persisting data and rehydration using the local storage but I am unable to do so. I have made a sandbox link to try and replicate the issue. Can someone help or guide me on what I may be doing wrong?

Thanks in advance

Codesandbox link: https://codesandbox.io/s/green-snow-ortw6?file=/src/App.js

arvir
  • 101
  • 1
  • 10

1 Answers1

3

You must pass the persisted state the first time that you invoke to useMachine, do not forget that useMachine is a closure, in that way it will work, for instance

import { useMachine } from "@xstate/react";
import { createMachine } from "xstate";
import { optionsConfig } from "./machine/machineDefinition";
import { machineConfig } from "./machine/machineDefinition";
import "./styles.css";
const machine = createMachine(machineConfig, optionsConfig);

export default function App() {
  const [state, notifyMachine] = useMachine(machine, {
    state: JSON.parse(localStorage.getItem("per_ste"))
  });
  const { context, value } = state;

  const onNextClick = () => {
    notifyMachine("NEXT");
  };

  const onPrevClick = () => {
    notifyMachine("BACK");
  };

  const onEventAClick = () => {
    notifyMachine("SEND_BUTTON_CLICKED", { data: "A" });
  };

  const onEventBClick = () => {
    notifyMachine("SEND_BUTTON_CLICKED", { data: "B" });
  };
  const onLogContextButtonClick = () => {
    console.log("CONTEXT:", context.eventTriggeredList);
  };
  const onLogStateButtonClick = () => {
    console.log("CONTEXT:", value);
  };

  const onPersistClick = () => {
    localStorage.setItem("per_ste", JSON.stringify(state));
  };
  const onRehydrateClick = () => {
    const persistedState = localStorage.getItem("per_ste");
    const parsedState = JSON.parse(persistedState);
    setPersistedState(parsedState);
  };

  return (
    <div className="App">
      <h1>Step Machine</h1>
      <h3>Start clicking to see some magic happen!</h3>
      <h2>{`Current Step: ${context.currentStepIndex}`}</h2>
      <div>
        <button onClick={onNextClick}>NEXT</button>
        <button onClick={onPrevClick}>PREV</button>
        <button onClick={onEventAClick}>SEND EVENT A</button>
        <button onClick={onEventBClick}>SEND EVENT B</button>
      </div>
      <br />
      <div>
        <button onClick={onLogContextButtonClick}>console Events</button>
        <button onClick={onLogStateButtonClick}>console Current State</button>
      </div>
      <br />
      <br />
      <div>
        <button onClick={onPersistClick}>PERSIST STATE</button>
        <button onClick={onRehydrateClick}>REHYDRATE STATE</button>
      </div>
    </div>
  );
}
luisbar
  • 676
  • 5
  • 11
  • Thanks a lot! That was really insightful. The current issue has been solved as per your suggestion, though this has lead to another roadblock. My intention was to have the machine state rehydrated on the fly which isn't possible now since it seems as though persisted state value is only read when the machine is initialised. It looks as though the only way to achieve this is would be to have the component containing the machine unmounted and then having it remounted with the required state config object. Is there some other way to have this solved? – arvir Dec 28 '21 at 19:41
  • Maybe spawning an actor (https://xstate.js.org/docs/guides/actors.html#spawning-actors), I don't know if this receives a persisted state, but you can try it out – luisbar Dec 28 '21 at 19:51
  • Thanks! Appreciate the quick response and i shall look into spawned actors. The only reference i had about something remotely similar was this thread on github (https://github.com/statelyai/xstate/discussions/1751) so this definitely seems like a new perspective. I guess i shall start another thread on SO if this doesn't work out :) . – arvir Dec 28 '21 at 19:58
  • you are welcome! :), let me know how do you do with that. By the way, I am working on this dashboard https://gitlab.com/luisbar/selling-point-admin-dashboard which uses XState, maybe it can useful for you – luisbar Dec 28 '21 at 20:31
  • the dashboard project certainly seems interesting :D. I guess i will have a detailed look into it over the weekend to see if it helps me out. I shall also let you know if I make some progress with the spawned progress approach (y). – arvir Dec 28 '21 at 20:41