XState

xstate

XState 是一个状态管理(State Management)的 Library,负责储存及描述各种状态与各种状态间的转换,有点类似于 Redux、Flux,不同的地方在于 XState 整个核心都源自于 Statecharts,也就是我们需要定义好整个应用,程序会有哪些状态,和每个状态下能转换到哪些状态(顺序性)以及他们之间如何转换。

Statecharts

其实 Statecharts 并不是什麽新技术或新概念,早在 1984 年 David HAREL 的论文就提出了 Statechart,是由早期的状态图(state diagrams)所拓展而来的,在该篇论文中对状态图加入了三个元素分别处理了层级(hierarchy)、併发(concurrency)和通讯(communication)。让原先的状态图变的高度结构化且能更有效地描述各种状态。

Statecharts 来描述 Fetch

为何需要 xstate?

其实用过 Angular.js 的开发者都会知道状态管理的重要性,当应用,程序状态分散在不同地方时,就会使得状态难以管理,并且容易出现 Bug,直到 Flux 出现提出了单一资料源(Single Source of Truth)及单向资料流(unidirectional data flow)等概念后,状态管理的问题才得到了缓解。而 Redux 的出现利用 Funtional Programming 的手法大幅度的降低原先 Flux 的複杂度以及学习成本,如果我们依照 Redux 的架构已经可以把因为状态複杂度而陡然上升的维护成本控制得很好,那如今为什麽我们还需要一个新的状态管理工具呢?

缺乏清晰的状态描述

不管是使用 Redux 或其他相关的 Library 都会有状态难以清晰描述的问题,最主要原因有两个,第一个是我们完全混合了状态(state)跟资料(context),所有东西都直接往 Reducer 裡面塞导致我们无法分清楚哪些是资料、哪些是状态。这裡的资料(context)指的是显示在页面上的内容,通常这些资料会存储在后端并透过 API 取得,在 XState 称之为 context,在 UML State Mechine 裡面称为 Extended states;而状态(state)则是指应用,程序当前的状态,比如说是否已登入或者 Menu 是否展开等等状态。

另一个因素是我们通常都使用 flag 来表达某个小状态,再由多个 flags 来表达某个状态,当这种 flag 越来越多时,我们的,程序就会很容易出现 Bug,,程序码会长的像下面这样:

if (isLogin && isYYY && isXXX)

这样的,程序码其实就是所谓的 bottom-up code,通常是我们先有一个小状态比如说 isLogin 然后后面又加了其他各种状态,当我们这种小状态一多,就会让,程序容出现难以察觉的 Bug。

过于自由的状态转换

如上面我们提到的,过去我们的状态是由多个 flags 所组成,这导致了我们无法明确的定义各种状态之间的关係,最后就会变成我们无法确定状态之间的切换是否正确,比如说 isAdmin 为 true 时 isLogin 应该必定为 true。像这样用 flag 储存小状态就会有可能出现状态转换出错的情况,比如说 isAdmin 设定成 true 了,却忘记把 isLogin 也设定为 true;而实际上状态的複杂度会比这裡举的例子複杂许多,这样的,程序码大到一定程度就会变成我们再也无法真正理解,程序有哪些状态,以及哪些可能的状态应该被处理(除非你再从头跟 PM 及 Designer 完整的过一次流程与画面,但如果专案够大很有可能他们也不会很清楚)。

难以与工程师之外的人讨论

同样的当我们今天用各种 flags 的方式去描述整个应用,程序的状态时,其实是很难跟工程师之外的人沟通或讨论的,就算是工程师也要追 Code 花时间理解当前的,程序到底是如何运作并且在哪个状态下出现的 Bug,这会让我们很难快速地发现问题也很难跟 PM 讨论需求设计是否存在逻辑上的矛盾,或是有未处理的状态。

XState 有什麽优势?

,程序码即 UI Spec

当我们今天用 XState 定义好各种状态之后,就可以直接利用 XState 提供的图像化工具(Visualizer)把,程序码转换成图片,如下:

xstate 状态逻辑图

当我们有这张图之后,就可以把这个当作 UI Spec 跟 PM 及设计师讨论哪方面流程有问题,或是还有哪些没有明确订定的状态。

写更少的测试

由于我们已经明确定义出各个状态以及每个状态之间的关係,这让我们可以更轻鬆的撰写测试,也不需要测试那些根本不可能出现的状态,并透过 Model-based Testing 我们只需要写各个状态下的断言(assertion)就可以自动把各种状态切换的路径都测试完!XState 在这方面也提供了 xstate-test 有完整的范例跟教学。

更快速的路径优化

当我们完成一个应用,程序时,最需要做的通常就是使用者体验(User Experience)的优化,我们常常需要利用各种服务来收集各个页面间的转化率或是哪些状态让使用者最快跳过等等的数据。透过这些数据来优化我们应用,程序的流程,让使用者体验进一步的提升。而如果使用了 XState 我们就可以在各个状态转换之间送 log 到数据收集的服务(如 GA, MIXpanel 等等),就可以进一步分析哪些状态可能是不必要的,来优化我们的 User Flow。