比如說我們這台狀態機想要給許多不同的店家共用,比如「綠洲酒吧」、「蘋果旗艦店」...
難道我需要一直寫一堆 appleStoreMachineConfig
, oasisBarMachineConfig
卻只有 context 些微不一樣嗎?
答案是「不用的」
const createDoorMachine = (shopName) => {
return createMachine({
id: 'door',
// shopName 來自 function 參數
context: {
shopName
}
// ...
});
};
const appleStoreDoorMachine = createDoorMachine('蘋果旗艦店');
const oasisBarDoorMachine = createDoorMachine('綠洲酒吧');
XState 的 machine 除了 someMachine.transition(state, event)
之外,也有提供方法 someMachine.withContext(...)
讓我們能得到一台新的被動態加載 context 的狀態機裡。
const someContext = { shopName: "蘋果旗艦店" };
const dynamicDoorMachine = doorMachine.withContext(someContext);
const service = interpret(dynamicDoorMachine).onTransition((state) => {
console.log(`State is ${state.value}`);
});
比如說今天我們「蘋果旗艦店」想要改店名成「蘋果尊絕不凡旗艦店」,我可以直接在狀態機裡面修改 context value 嗎?
可以的! XState 官方提供給我們另外一個 API assign
(指派),讓我們可以在 action 時,指定、修改 context 。
TLDR: codeSandbox DEMO
前情提要:Action 被觸發的三種時機
讓我們來看看如何修改店名,假設我們今天進開門時會看到 「蘋果尊絕不凡旗艦店」關門時會看到「蘋果旗艦店」的 LED 燈閃爍。
先來看看 assign
怎麼用!~ assign
是個 higher order function ,它會被先被定義 Action 發生時該怎麼更新 context,然後當實際 Action 發生時,就會去執行 assign
內被定義的修改方式!
assign
吃一個 object 參數,key 是想要被更新的 context value 的 key,以本例而言,就是我們的 shopName
而這個 object 的 value 會是什麼呢? 就是定義如何更新 context 的 function,這個 function 運算回傳的結果,就是更新後的 context 。
assign({
shopName: (context, event) => "蘋果旗艦店"
}),
assign({
shopName: (context, event) => "蘋果尊絕不凡旗艦店"
}),
所以這個 assign 會被放在哪裡呢?它可以被放在前情提要的三個地方
{
actions: {
拉開大門: () => console.error("side effect..........拉開厚重的門...."),
關上大門: () => console.error("side effect..........推回厚重的門...."),
+ "LED 顯示": (context, event) => console.log(`${event.type}!~ LED 顯示 『${context.shopName}』`),
}
}
開門時會看到 「蘋果尊絕不凡旗艦店」關門時會看到「蘋果旗艦店」的 LED 燈閃爍。
想必 我們應該是需要在 entry 進去 state 之前,先修改 context ,然後執行 "LED 顯示" 的 side effect
因此我們會將這個需求定義在 entry action 裡,前面提及 Action 可以有複數個...
我們在此新增定義進我們的 machineConfig,如此,進入到「開了」的狀態之前,我們會先
"蘋果尊絕不凡旗艦店"
"LED 顯示"
來跟我們的客戶打招呼 開了: {
entry: [
assign({
shopName: (context, event) => "蘋果尊絕不凡旗艦店"
}),
"LED 顯示"
],
on: {
關門: { target: "關著", actions: ["關上大門"] }
}
}
同理,進入到「關著」的狀態之前,我們會先
"蘋果旗艦店"
"LED 顯示"
來跟我們的客戶打招呼 關著: {
entry: [
assign({
shopName: (context) => "蘋果旗艦店"
}),
"LED 顯示"
],
on: {
開門: { target: "開了", actions: ["拉開大門"] }
}
},
明天~我將會努力舉更貼近現實一點的例子 >_<
大家一起加油~~~!
https://xstate.js.org/docs/guides/context.html
https://xstate.js.org/docs/guides/action.html
話說 同理,進入到「關著」的狀態之前,我們會先
下方的 code 好像錯了,附到「開了」的
ohQQ
謝謝~貼錯了沒注意到