如何在 Xstate 状态机中保持状态以做出反应?
How to persist state in Xstate state machines in react?
我有一个可以工作的购物车状态机,可以在我使用 reactjs 的购物车中添加商品。在刷新页面上,上下文不是 persisted.I`m 状态机的新内容,并且想在我的 app.Below 是我的 cartMachine 中保持状态。请 help.Thank 你。
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 });
}
}),
},
}
);
您必须将状态上下文保存在浏览器的本地存储中,以便即使在页面刷新时也能持久保存。它非常简单 API,您可以在以下位置阅读更多信息:https://www.w3schools.com/jsref/prop_win_localstorage.asp
@muhammad-ali 的回答回答了您的特定问题。当您刷新浏览器时,内存中的任何 data/application 状态都会消失。您将需要找到其他解决方案来永久保留刷新之间的数据。不过,这与 XState 或 React 无关。由于您的目标似乎是将商品存储在购物车中,因此如果用户返回该站点他仍然拥有相同的购物车,您将不得不使用 localStorage
或使用后端 + 数据存储来永久保存数据并在加载 application/cart 页面时通过 API 检索数据。
答案的其余部分与原始问题有些偏离,但可能会提供一些关于机器状态实际上如何使用 XState 机器持久保存在内存中的见解。
机器本身不会持久化状态(甚至在某种程度上也不在内存中)。显示这一点的示例是,如果你做一台机器 transition
(传递初始状态和你想要执行的操作)然后读取机器状态之后它仍将处于原始状态。 XState 机器基本上只是可以执行操作(作为转换)的东西,这个转换 returns 给你的新状态。
问题中使用你的机器:
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
所以机器永远不会持久化状态。不过,您有两种选择来实现这一目标。
将每次转换后的新状态存储在 React 状态的某处。 XState 机器状态是 JSON 可序列化的,因此您可以毫无问题地存储在 React 状态中。
使用机器服务来保存状态 (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
xState documentation 中有一个很好的例子,展示了他们如何建议使用 localStorage
:
You can persist and rehydrate state with useMachine(...) via options.state:
// ...
// 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 (/* ... */)
}
我有一个可以工作的购物车状态机,可以在我使用 reactjs 的购物车中添加商品。在刷新页面上,上下文不是 persisted.I`m 状态机的新内容,并且想在我的 app.Below 是我的 cartMachine 中保持状态。请 help.Thank 你。
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 });
}
}),
},
}
);
您必须将状态上下文保存在浏览器的本地存储中,以便即使在页面刷新时也能持久保存。它非常简单 API,您可以在以下位置阅读更多信息:https://www.w3schools.com/jsref/prop_win_localstorage.asp
@muhammad-ali 的回答回答了您的特定问题。当您刷新浏览器时,内存中的任何 data/application 状态都会消失。您将需要找到其他解决方案来永久保留刷新之间的数据。不过,这与 XState 或 React 无关。由于您的目标似乎是将商品存储在购物车中,因此如果用户返回该站点他仍然拥有相同的购物车,您将不得不使用 localStorage
或使用后端 + 数据存储来永久保存数据并在加载 application/cart 页面时通过 API 检索数据。
答案的其余部分与原始问题有些偏离,但可能会提供一些关于机器状态实际上如何使用 XState 机器持久保存在内存中的见解。
机器本身不会持久化状态(甚至在某种程度上也不在内存中)。显示这一点的示例是,如果你做一台机器 transition
(传递初始状态和你想要执行的操作)然后读取机器状态之后它仍将处于原始状态。 XState 机器基本上只是可以执行操作(作为转换)的东西,这个转换 returns 给你的新状态。
问题中使用你的机器:
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
所以机器永远不会持久化状态。不过,您有两种选择来实现这一目标。
将每次转换后的新状态存储在 React 状态的某处。 XState 机器状态是 JSON 可序列化的,因此您可以毫无问题地存储在 React 状态中。
使用机器服务来保存状态 (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
xState documentation 中有一个很好的例子,展示了他们如何建议使用 localStorage
:
You can persist and rehydrate state with useMachine(...) via options.state:
// ...
// 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 (/* ... */)
}