redux 和状态机(例如 xstate)之间的实际区别是啥?

Posted

技术标签:

【中文标题】redux 和状态机(例如 xstate)之间的实际区别是啥?【英文标题】:What is an actual difference between redux and a state machine (e.g. xstate)?redux 和状态机(例如 xstate)之间的实际区别是什么? 【发布时间】:2019-06-26 05:15:52 【问题描述】:

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

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

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

我从未使用过 xstate,所以我觉得它很有趣,并开始阅读文档并查看不同的示例。看起来很有前途和强大,但在某些时候我明白我没有看到它和 redux 之间有任何显着差异。

我花了几个小时试图找到答案,或者比较 xstate 和 redux 的任何其他信息。除了 "get from redux to a state machine" 之类的一些文章,或者专注于使用 redux 和 xstate together 的库的链接(很奇怪)之外,我没有找到任何明确的信息。

如果有人可以描述差异或告诉我开发人员何时应该选择 xstate - 欢迎您。

【问题讨论】:

官方文档实际上说你应该把你的redux reducer当作一个状态机redux.js.org/style-guide/… 我认为您提到的库可能是用于使用 xstate 作为效果管理系统(替代 thunk、saga、epic 等) 【参考方案1】:

我创建了 XState,但我不会告诉你是否要使用其中一个;这取决于你的团队。相反,我将尝试强调一些关键差异。

Redux XState
essentially a state container where events (called actions in Redux) are sent to a reducer which update state also a state container, but separates finite state (e.g., "loading", "success") from "infinite state", or context (e.g., items: [...])
does not dictate how you define your reducers - they are plain functions that return the next state given the current state and event (action) a "reducer with rules" - you define legal transitions between finite states due to events, and also which actions should be executed in a transition (or on entry/exit from a state)
does not have a built-in way to handle side-effects; there are many community options, like redux-thunk, redux-saga, etc. makes actions (side-effects) declarative and explicit - they are part of the State object that is returned on each transition (current state + event)
currently has no way to visualize transitions between states, since it does not discern between finite and infinite state has a visualizer: https://statecharts.github.io/xstate-viz which is feasible due to the declarative nature
the implicit logic/behavior represented in reducers can't be serialized declaratively (e.g., in JSON) machine definitions, which represent logic/behavior, can be serialized to JSON, and read from JSON; this makes behavior very portable and configurable by external tools
not strictly a state machine adheres strictly to the W3C SCXML specification: https://www.w3.org/TR/scxml/
relies on the developer to manually prevent impossible states uses statecharts to naturally define boundaries for handling events, which prevents impossible states and can be statically analyzed
encourages the use of a single, "global" atomic store encourages the use of an Actor-model-like approach, where there can be many hierarchical statechart/"service" instances that communicate with each other

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

【讨论】:

终于有人使用 FSM 和 SCXML 进行前端开发......你救了我的命,我要去研究你的图书馆。由于某些原因,我不喜欢 redux(首先它混淆了事件和操作术语),其次它使用数百万个标志“建模”复杂状态(冗长且恕我直言不正确)。 @Mike76 XState 与 Redux 开发工具集成。 感谢您的提示,我会调查的。 我现在已经尝试过 XState + Redux DevTools。它工作得很好,但似乎缺少一些功能。例如,XState + Redux DevTools 不支持像“状态重放”这样的功能,即重放一系列先前的状态。这是由于实施限制吗? @Mike76 在 Redux 和 XState 的时间旅行中看到这个:github.com/statelyai/xstate/issues/906#issuecomment-569760677【参考方案2】:

状态机不会告诉(强制)您拥有单向数据流。它与数据流无关。更多的是关于约束状态变化状态转换。因此,通常只有当您需要约束/禁止某些状态更改并且您对转换感兴趣时,才会使用状态机设计应用程序的某些部分。

请注意,对于状态机,如果出于某种原因(外部 API 依赖等...),应用可能会被锁定在某个状态,由于限制而无法转换到另一个状态,您必须解决它。

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


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

【讨论】:

FSM 不就是一个能驱动 Redux 的图吗?导航是 FSM,因为您有后退按钮。除非你禁用后退按钮,否则即使在 Redux 中,你也有一个 FSM。 Redux 是一种具有良好约束的不可变数据模式。因此,当您浏览您的 FSM(库或自己编写的,即使是无意的)时,Redux 可以防止副作用。 Redux 仅捕获数据流的单向部分。它不纯。【参考方案3】:

我的几点如下。

UI 状态和业务/后端状态在 redux 中耦合在一起。因此,对 ui 或业务状态的每次更新都会在 redux 存储中创建一个数据更新。 Xstate 将 UI 状态和后端状态解耦。 在 redux 中,所有节点都存在于根节点内。 Xstate 在独立的机器中分散和分发数据。 应用程序只能在已定义的状态之间转换。因此机器本身可以修复任何错误或错误。 内部状态由机器本身在 Xstate 中管理。 Redux 将新状态表示为标志。 渲染器竞争 - 将尽可能多的状态提升到机器中,如果需要,我们可以相对容易地切换渲染框架(例如从 react 到 vue)。 Contexts 提供了具体的类来向外界呈现一个单一的接口。

【讨论】:

以上是关于redux 和状态机(例如 xstate)之间的实际区别是啥?的主要内容,如果未能解决你的问题,请参考以下文章

XState Viz 可视化和调试状态机

XState Viz 可视化和调试状态机

XState Viz 可视化和调试状态机

如何在反应中保持 Xstate 状态机中的状态?

如何使用 xstate 跟踪分析事件

前端状态机:XState 首个中文文档上线了