我正在研究一种中等复杂度的前端应用程序.此时它是用纯JavaScript编写的,它有很多不同的基于事件的消息,连接了这个应用程序的几个主要部分.
我们决定显然我们需要在进一步重构的范围内为这个应用程序实现某种状态容器.以前我有一些使用redux和ngrx存储的经验(实际上遵循相同的原则).
Redux是我们的选择,但其中一个开发人员建议使用状态机,特别是xstate库.
我从来没有使用过这个东西,所以我发现它很有趣,并开始阅读文档并查看不同的例子.看起来很有前途和强大,但在某些时候我明白我没有看到它和redux之间的显着差异.
我花了好几个小时试图找到答案,或者与比较xstate和redux或者一些"利弊"相关的任何其他信息.不幸的是,我最终弄得一团糟.我没有找到任何明确的信息,除了像一些文章"从终极版以状态机得到",或指向集中于使用终极版和XSTATE库一起,并且终于突破了我.
如果有人可以描述差异或告诉我何时开发人员应该选择xstate - 欢迎你.
谢谢.
我已经广泛阅读了文档,但是,仍有一些部分不完全清楚,大多数与演员/服务有关
我对生成的演员生命周期的细节有点模糊。
.stop()带有生成的演员的服务也会.stop()是生成的演员还是他们被悬着?children从服务本身内部访问生成的演员?(就像从一个动作内部)假设我有一台带有添加文件操作的机器。添加文件时,会spawn()为其调用新文件,并将引用存储到context. 现在,当机器完成不管它在做什么,我想重置context并清除children后,.stop()荷兰国际集团各一台。
这里要完全具体地说明我是如何对实现上述行为的上传系统进行建模的。
在这个实现中,每当机器返回到idle状态时,我都会重置context并手动.stop()调用每个生成的 actor。但是,actor 服务仍然在 中徘徊.children,我无法从机器操作内部访问它们(将第三个参数添加meta到resetContext不会导致任何可以访问当前的children)。
关于.stop()ing 演员并清除children和重置context,理想情况下,我希望为每个演员单独采取行动,在idle进入状态时运行,但是由于我似乎无法找到一种访问方式children,因此通过一个动作完成所有操作这context是我能想到的唯一解决方案。
另外,请注意,在官方示例中,当 todo 被删除时,其生成的 actor 不是.stop()ed,这让我想知道这是疏忽还是有原因?
下面,为方便起见,是实现上传系统和文件的代码。完整的实现,其中还包括可视化器,可以在这里找到:
// upload system machine
const uploadSystemMachine = Machine(
{
id: 'upload-system',
initial: …Run Code Online (Sandbox Code Playgroud) 我需要将事件发送到另一个生成的状态机,其 ID 作为上下文中变量中的字符串。(它不是父状态机,也不是子状态机)
喜欢
context.sendTo = 'B_id'
如何处理send()上下文中的参数?
以及如何放入send('MY_EVENT_NAME', {to: <something from context> })该MachineOptions actions部分?
// this does not work...
const myMachineOptions:Partial<MachineOptions<any,any>> =
{
actions:{
mySend: (context, event)=>send('MY_EVENT_NAME', {to: context.sendTo })
}
}
Run Code Online (Sandbox Code Playgroud)
聚苯乙烯
就像 xState 中将事件从一台机器发送到另一台机器时的传递值一样
但我需要动态的不是消息正文而是to:部分
我计划使用 XState 来管理应用程序后端的状态。当调用 api 时,状态更改成功时将调用一个函数。函数调用的结果必须作为 api 的响应返回。
// Returns a Promise, e.g.:
// {
// id: 42,
// name: 'David',
// friends: [2, 3, 5, 7, 9] // friend IDs
// }
function getUserInfo(context) {
return fetch('/api/users/#{context.userId}').then(response =>
response.json()
);
}
// Returns a Promise
function getUserFriends(context) {
const { friends } = context.user;
return Promise.all(
friends.map(friendId =>
fetch('/api/users/#{context.userId}/').then(response => response.json())
)
);
}
const friendsMachine = Machine({
id: 'friends',
context: { userId: 42, user: undefined, friends: undefined },
initial: …Run Code Online (Sandbox Code Playgroud) 我有一个工作购物车状态机来添加我正在使用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) 我有一个多步骤表单,基本上包含以下基本步骤:select services -> contact -> billing。当用户更改他们所在的步骤时,我显示进度条并发出事件,这是我当前使用 xstate 的基本模式:
const formMachine = new Machine({
id: 'form-machine',
initial: 'selectService',
context: {
progress: 0,
pathname: '/select-service',
},
states: {
selectService: {
entry: assign({
progress: 0,
pathname: '/select-service',
}),
on: {
NEXT: 'contact',
}
},
contact: {
entry: assign({
progress: 1 / 3,
pathname: '/billing'
}),
on: {
PREVIOUS: 'selectService',
NEXT: 'billing',
}
},
// ... there's more actions but that's the gist of it
}
});
Run Code Online (Sandbox Code Playgroud)
在我的反应组件中,我观察该服务的变化,pathname以便我可以推送历史记录
function …Run Code Online (Sandbox Code Playgroud) 我对演员和在 xstate 中调用服务之间的区别有点困惑,因为它们在我看来是一样的。
我有一系列在本地通过的快照测试。但在 Jenkins 上,我的组件似乎正在渲染不同的快照。我的测试是:
import { render } from 'enzyme';
import React from 'react';
import Wizard from '../index';
describe('Wizard', () => {
describe('Snapshot tests', () => {
it('Should render the Wizard', () => {
const container = render(<Wizard />);
expect(container).toMatchSnapshot();
});
});
});
Run Code Online (Sandbox Code Playgroud)
我的组件:
const Wizard = (): JSX.Element => (
<FTWizard
tree={root}
layouts={{
layout1: Layout1,
layout2: Layout2,
layout3: Layout3,
}}
stepsContent={{
layout1: Layout1Content,
layout2: Layout2Content,
layout3: Layout3Content,
}}
/>
);
export default Wizard;
Run Code Online (Sandbox Code Playgroud)
我正在使用酶生成快照,我的组件正在使用 xstate 机器。在本地测试时一切正常,但在 Jenkins 上我收到以下错误:
Stacktrace
Error: …Run Code Online (Sandbox Code Playgroud) 我正在学习 XState,并希望在机器中包含一个仅将当前状态记录到控制台的操作。
像这样定义一个简单的示例机器,我将如何去做呢?另请注意代码中注释中的问题。
import { createMachine, interpret } from "xstate"
const sm = createMachine({
initial: 'foo',
states: {
foo: {
entry: 'logState', // Can I only reference an action by string?
// Or can I add arguments here somehow?
on: {
TOGGLE: {target: 'bar'}
}
},
bar: {
entry: 'logState',
on: {
TOGGLE: {target: 'foo'}
}
}
}
},
{
actions: {
logState(/* What arguments can go here? */) => {
// What do I do here?
}
}
}); …Run Code Online (Sandbox Code Playgroud) 取以下有限状态机:
const machine = Machine({
initial: "foo",
states: {
foo: {
on: {
BAZ: "baz",
QUX: "qux",
},
},
bar: {
on: {
BAZ: "baz",
QUX: "qux",
},
},
baz: {
on: {
FOO: "foo",
BAR: "bar",
},
},
qux: {
on: {
FOO: "foo",
BAR: "bar",
},
},
},
});
Run Code Online (Sandbox Code Playgroud)
请注意,有两组重复的状态转换:
on: {
FOO: "foo",
bar: "bar",
}
Run Code Online (Sandbox Code Playgroud)
on: {
BAZ: "baz",
QUX: "qux",
}
Run Code Online (Sandbox Code Playgroud)
除了在 Machine 定义之外将状态转换定义为好的 ol' JavaScript 对象,是否有一种特殊的方法来做到这一点?
xstate ×10
javascript ×7
reactjs ×4
state ×2
enzyme ×1
fsm ×1
jestjs ×1
node.js ×1
redux ×1
typescript ×1