Day21 - 在 XState, 状态机器里无穷尽的状态、 资料:Extended State and context - 1

1. Extended State

前面学习到的 FSM ,我们透过枚举、列举 (Enumerate),一个状态机内所有可能的状态,状态机被提供的状态是有限(Finite)的,所以叫我们称之为有限状态机 (Finite State Machine)。

但现实中的状态机里,我们可能会有些状态是无限的、或是我们希望能带某些资料(data)进去状态机里供其使用...
我们将这些无穷的状态、资料称之为 "Extended State"(扩充的状态)。

比如说有一个水的状态机,水可能会有「液态」、「固态」、「气态」的三种状态,但有时我们希望这组状态机也能储存当前水容量(amount)的资讯,这个水容量无法用 1,2,3... 列举完,水量可能是无穷尽的。

在 XState 里面的 Extended State 被称作 "context"

我们继续以底下这个状态机为范例
https://ithelp.ithome.com.tw/upload/images/20210926/20130721htU67KKipL.png

我们要怎麽带额外的资料进去状态机内呢?
比如说这个门可能是属於不同家店的,可能会有店名像是「绿洲酒吧」、「苹果旗舰店」或是任何使用者输入...,我们一时间无法列举出所有可能...,但当我在判断状态转换的防御(Guard)、又或是执行 side effect 的 action 需要这个资料时,该怎麽办?

2. Context

我们一样可以把这个资料写进去 machineConfig

  const doorMachine = createMachine(
    {
      // Machine identifier
      id: "door",
      // Initial context
+      context: {
+        shopName: "苹果旗舰店"
+      },
      // Initial state
      initial: "关着",

      // State definitions
      states: {...}
    },  extraOptions)

接下来我们在回去看昨天的 Action

  {
    actions: {
      拉开大门: (c, e) =>
        console.error("side effect..........拉开厚重的门...."),
      关上大门: () => console.error("side effect..........推回厚重的门....")
    }
  }

有注意到『拉开大门』这个 side effect ,的 (c, e) 终於可以在今天一起介绍了,那个 c 就是 context(Extended State); e 就是 event (事件),也就是当我们在执行『拉开大门』时,我们可以拿到状态机里的资料及当下这个事件,我们可以直切印出 c,e 看看

  {
    actions: {
      拉开大门: (c, e) =>
-       console.error("side effect..........拉开厚重的门...."),
+       console.error(c, e, "side effect..........拉开厚重的门...."),
      关上大门: () => console.error("side effect..........推回厚重的门....")
    }
  }

https://ithelp.ithome.com.tw/upload/images/20211006/20130721CnQE7sQFBm.png

codesandbox DEMO

如此我们就能拿到这个被延伸、被状态机记忆且共享的资料了

问题延伸

请问如何动态载入不同的 context ?

比如说我们这台状态机想要给许多不同的店家共用,比如「绿洲酒吧」、「苹果旗舰店」...

难道我需要一直写一堆 appleStoreMachineConfig, oasisBarMachineConfig 却只有 context 些微不一样吗?

请问我有办法修改 context 的值吗?

比如说今天我们「苹果旗舰店」想要改店名成「苹果尊绝不凡旗舰店」,我可以直接在状态机里面修改 context value 吗?

这两个问题将在明天一起被回答~

参考文献

https://en.wikipedia.org/wiki/UML_state_machine
https://xstate.js.org/docs/guides/context.html#initial-context


<<:  dict查表进阶用法 - 使用部分字串查询是否存在任一key中

>>:  Service Container

[Day17] 一级函式

这边从 008 的 Day5 开始,先跳过 Day3、Day4 篇浏览器的部分。 一级函式 函式是物...

【Day 16】- 做 Excel 输入数据到心累?消警告的服学输入很繁琐? 使用 openpyxl 来操作 Excel

前情提要 前一篇带各位实作了爬取币种汇率的爬虫。 开始之前 本篇将带各位在 Python 中操作 E...

Ruby幼幼班--Factorial Trailing Zeroes

9月快到了,要开始准备一些资料,凑30天用,所以除非有一篇Rails幼幼班的资料,不然不会单独分享...

<Day9> Contract — 取得期货(Futures)资讯

● 这章将以模拟帐户来示范如何取得期货(Futures)资讯 回顾上一章,我们学习如何用Contra...

使用MongoDB -- 资料库简易上手

1. 注册及登入mongo database 2. Altas 点这边 之後应该会出现这个画面 点击...