如何在React中保存Xstate状态机中的状态?

Ric*_*mes 5 javascript state-machine reactjs xstate

我有一个工作购物车状态机来添加我正在使用reactjs 的购物车中的商品。在刷新页面时,上下文未保留。我是状态机新手,想在我的应用程序中保留状态。下面是我的购物车。请帮助。谢谢。

export const cartMachine = Machine(
  {
    id: "cart",
    initial: "idle",
    context: {
      ItemsInCart: [],
    },
    states: {
      idle: {
        on: {
          ADD: {
            target: "idle",
            actions: ["addProductsToCart"],
          },
        },
      },
    },
  },
  /* actions */
  {
    actions: {
      addProductToCart: assign((context, event) => {
        const { ItemsInCart } = context;
        const { item } = event;
        let checkIfProductInCart = ItemsInCart.find(({ id }) => id == item.id);
        let canAddToCart = checkIfProductInCart;

        if (!canAddToCart) {
          ItemsInCart.push({ ...item });
        }
      }),
    },
  }
);
Run Code Online (Sandbox Code Playgroud)

Tor*_*cht 7

@muhammad-ali 的答案回答了您的特定问题。当您刷新浏览器时,内存中的任何数据/应用程序状态都会消失。您将需要找到其他解决方案来永久保留刷新之间的数据。但这与 XState 或 React 无关。由于您的目标似乎是将商品存储在购物车中,因此如果用户返回网站,他仍然拥有相同的购物车,您将必须使用localStorage或使用后端+数据存储来永久保存数据并通过以下方式检索数据当您加载应用程序/购物车页面时的 API。

答案的其余部分与最初的问题有些偏离,但也许提供了一些关于如何使用 XState 机器将机器状态实际保存在内存中的见解。

机器本身并不持久保存状态(甚至在某种程度上也不保存在内存中)。说明这一点的示例是,如果您执行一台机器transition(传递初始状态和要执行的操作),然后读取机器状态,那么它仍将处于原始状态。XState 机基本上只是可​​以执行操作(作为转换)的东西,并且此转换将新状态返回给您。

在问题中使用您的机器:

const cartMachine = Machine({ ... })

const newState1 = cartMachine.transition(cartMachine.initialState, {type: 'ADD', item: {...})
console.log(newState1.context.ItemsInCart)  // Will contain item

const newState2 = cartMachine.transition(cartMachine.initialState, {type: 'ADD', item: {...})
console.log(newState2.context.ItemsInCart)  // Will still only contain one item (from the last ADD operation)

// can not read the current state from machine, only initialState is available
console.log(cartMachine.initialState.context.ItemsInCart)  // will still be []

// You will have to persist state yourself
const newState1 = cartMachine.transition(cartMachine.initialState, {type: 'ADD', item: {...})
// Pass the new state into the machine
const newState2 = cartMachine.transition(newState1, {type: 'ADD', item: {...})
console.log(newState2.context.ItemsInCart)  // Will now contain two items
Run Code Online (Sandbox Code Playgroud)

所以机器永远不会持久化状态。不过,您有两种选择来实现这一目标。

  1. 每次转换后将新状态存储在 React 状态中的某个位置。XState 机状态是 JSON 可序列化的,因此您可以毫无问题地存储在 React 状态中。

  2. 使用机器服务来保存状态(https://xstate.js.org/docs/guides/interpretation.html)。只要您使用该服务的同一实例,每个转换都会保留在内存中,直到服务停止。您的机器的示例:

import { Machine, assign, interpret } from 'xstate'

const cartMachine = Machine({ ... })

const cartService = interpret(cartMachine)
cartService.start()

cartService.send({type: 'ADD', item: {...})
console.log(cartService.state.context.ItemsInCart)  // contains item

cartService.send({type: 'ADD', item: {...})
console.log(cartService.state.context.ItemsInCart)  // contains 2 items
Run Code Online (Sandbox Code Playgroud)


jfu*_*unk 5

xState 文档中有一个很好的示例,展示了他们建议如何使用localStorage

您可以通过 options.state 使用 useMachine(...) 持久保存和补充状态:

// ...

// Get the persisted state config object from somewhere, e.g. localStorage
const persistedState = 
  JSON.parse(localStorage.getItem('some-persisted-state-key') || 
  someMachine.initialState;

const App = () => {
  const [state, send] = useMachine(someMachine, {
    state: persistedState // provide persisted state config object here
  });

  // state will initially be that persisted state, not the machine's initialState

  return (/* ... */)
}
Run Code Online (Sandbox Code Playgroud)