Redux和状态机(例如xstate)之间的实际区别是什么?

183

我正在研究一个中等复杂度的前端应用程序。目前它是纯javascript编写的,有很多不同的基于事件的消息连接该应用程序的几个主要部分。

我们决定在进一步重构的范围内为该应用程序实现某种状态容器。以前我有过redux和ngrx store的一些经验(实际上遵循相同的原则)。

Redux是我们的选择,但其中一位开发人员建议使用基于状态机的库,特别是xstate库

我以前从未使用过xstate,所以我觉得很有意思,开始阅读文档并查看不同的示例。它看起来很有前途和强大,但是在某个时候,我明白了它与redux之间没有任何显著的区别。

我花了数小时尝试找到答案或任何其他比较xstate和redux的信息。除了类似于“从redux到状态机”的文章或者链接到专注于同时使用redux和xstate的库的文章(相当奇怪),我没有找到任何清晰的信息。

如果有人能描述出区别或告诉我开发者何时应该选择xstate - 欢迎。


11
官方文档实际上指出你应该将 Redux 中的 reducers 视为状态机。https://redux.js.org/style-guide/style-guide#treat-reducers-as-state-machines - Yannic Hamann
我认为你提到的库可能是用于将xstate作为效果管理系统(替代thunk、saga、epic等)使用的。 - Alfred Young
3个回答

385

我创造了XState,但我不会告诉你应该使用哪个;这取决于你的团队。相反,我将尝试突出一些关键区别。

Redux XState
本质上是一个状态容器,在 reducer 中更新状态时发送事件(在 Redux 中称为actions 也是一个状态容器,但将有限状态(例如"loading""success")与“无限状态”或上下文(例如items: [...])分离开
并不规定如何定义你的 reducers - 它们是简单函数,根据当前状态和事件(action)返回下一个状态 一个“带规则的reducer” - 你可以定义由事件引起的有限状态之间的合法转换,以及在转换中执行哪些操作(或在进入/退出状态时)
没有内置的方式来处理副作用;有许多社区选项,如 redux-thunk、redux-saga 等 使操作(副作用)声明式和明确 - 它们是每次转换(当前状态+事件)返回的State对象的一部分
目前没有办法可视化状态之间的转换,因为它不区分有限状态和无限状态有可视化工具:https://statecharts.github.io/xstate-viz,这归因于其声明式特性
在 Reducer 中表示的隐式逻辑/行为无法声明式地序列化(例如,在 JSON 中) 机器定义代表逻辑/行为,可以序列化为 JSON,并从 JSON 中读取;这使得行为非常易于移植和通过外部工具进行配置
不是严格的状态机 严格遵循 W3C SCXML 规范:https://www.w3.org/TR/scxml/
依赖开发人员手动防止不可能的状态 使用状态图自然定义处理事件的边界,防止不可能的状态并可静态分析
鼓励使用单个“全局”原子存储 鼓励使用类似 Actor 模型的方法,其中可以有许多层次结构的状态图/“服务”实例之间相互通信

本周我将添加更多关键差异到文档中。


22
终于有人在前端开发中使用有限状态机(FSM)和状态图扩展标记语言(SCXML)了……伙计,你救了我的命,我要研究一下你的库。我不喜欢 Redux,因为它混淆了事件和动作的术语,并且使用了数百个标志符号“模拟”复杂状态(冗长而且不正确)。 - Carlos Verdes
2
@Mike76 XState 可以与 Redux 开发工具集成。 - David Khourshid
谢谢你的提示,我会去了解一下。 - Mike76
1
我现在尝试了XState + Redux DevTools。它运行得相当不错,但是似乎缺少一些功能。例如,XState + Redux DevTools不支持“状态重放”等功能,其中会重放一系列先前的状态。这是由于实现限制吗? - Mike76
1
@Mike76 请查看Redux和XState中的时间旅行:https://github.com/statelyai/xstate/issues/906#issuecomment-569760677 - Magne

36

状态机并不强制要求您采用单向数据流。它与数据流无关,更多的是关于限制状态改变状态转换。因此,通常情况下只有应用程序的一些部分将被设计为状态机,仅当您需要限制/禁止某些状态变化且您对转换感兴趣时才会这样做。

请注意,使用状态机时,如果由于外部API依赖等原因,应用程序可能会陷入无法转换到另一个状态的状态中,因此您必须解决此问题。

但是,如果您只对最后的应用程序状态本身感兴趣,而不是对状态转换感兴趣,并且状态约束无关紧要,则最好不要使用状态机直接更新状态本身(您仍然可以将状态包装在Singleton类中,通过操作类进行更新)。


另一方面,Redux 是一个单向数据流的框架。 单向数据流强制你只能有单个数据流的方向。 在Redux中,它从User->View->(Action)->Store->Reducer->(Middleware)->Store->(State)->View 开始。像状态机一样,您可以使用Redux中的中间件触发副作用。如果需要,您可以约束/禁止状态转换。与状态机不同,Redux强制实现单向数据流,使用!的 reducer 函数、不可变的状态对象以及单个可观察应用程序状态。


1
有没有觉得FSM只是可以驱动Redux的图形呢?导航是一个FSM,因为你有返回按钮。除非你禁用返回按钮,即使在Redux中,你也有一个FSM。Redux是一种具有良好约束条件的不可变数据模式。因此,当您通过自己编写的FSM(库或自编)进行导航时,Redux可以防止副作用。Redux仅捕获数据流的单向部分。它并不是纯粹的。 - TamusJRoyce

1
以下是我的几个观点:
- 在Redux中,UI状态和业务/后端状态是耦合在一起的。因此,对UI或业务状态的每次更新都会在Redux存储中创建数据更新。 - Xstate将UI状态和后端状态解耦。 - 在Redux中,所有节点都存在于根节点内。Xstate将数据分散到独立的机器中。 - 应用程序只能在已定义的状态之间进行转换。因此,任何错误或漏洞都可以在机器本身中修复。 - 内部状态由Xstate的机器自己管理。Redux将新状态表示为标志。 - 渲染器不受限制-尽可能将状态提升到机器中,并且如果需要,我们可以相对容易地切换渲染框架(例如从React到Vue)。 - 上下文提供了一个具体的类,以向外界呈现单个接口。

1
我实际上对两者都很熟悉。但这并不完全准确。React主要只是将HTML渲染为函数。React提供了最小的状态处理,旨在用于简单的UI元素。对于“业务规则”,有许多第三方库,包括xstate。 - Arturo Hernandez
1
这篇文章比较了Redux和XState,特别是它们在React应用程序中的状态管理方面。 - Vijay122

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接