【问题标题】:How to persist state in Xstate state machines in react?如何在反应中保持 Xstate 状态机中的状态?
【发布时间】:2020-09-08 01:45:57
【问题描述】:

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

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 });
        }
      }),
    },
  }
);

【问题讨论】:

    标签: javascript reactjs state-machine xstate


    【解决方案1】:

    @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
    

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

    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
    

    【讨论】:

      【解决方案2】:

      xState documentation 中有一个很好的例子,展示了他们如何建议使用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 (/* ... */)
      }
      

      【讨论】:

        【解决方案3】:

        您必须将状态上下文保存在浏览器的本地存储中,以便即使在页面刷新时也能保留它。它具有非常简单的 API,您可以在以下位置了解更多信息:https://www.w3schools.com/jsref/prop_win_localstorage.asp

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-03-14
          • 2021-05-14
          • 1970-01-01
          • 1970-01-01
          • 2019-02-11
          • 1970-01-01
          • 1970-01-01
          • 2022-01-09
          相关资源
          最近更新 更多