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

What is an actual difference between redux and a state machine (e.g. xstate)?

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

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

Redux is an option for us, but one of the developers proposed using a state-machine based library, in particular the xstate library.

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

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

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

我创建了 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

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

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

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

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


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

以下是我的几点看法。

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