除蟲花掉的時間可長可短,是不可控的因素,它可能佔用了好幾個小時就為了一個錯誤。當應用程式越來越大時,定位錯誤成了問題。有些操作是在某特定狀況下操作才有意義,如果有一個狀態圖成為真相的來源是不是更好?
先來看一下原始代碼:
// viewing -> editing -> viewing
const [value, setValue] = useState('');
const [committedValue, setCommittedValue] = useState('');
const [mode, setMode] = useState('viewing');
const textEditStart = () => {
setValue(committedValue);
setMode('editing');
}
const textChange = (newValue) => {
setValue(newValue);
}
const textCommit = () => {
setCommittedValue(value);
setMode('viewing');
}
const textCancel = () => {
setValue(committedValue);
setMode('viewing');
}
狀態不一致的風險
// 可能出現的錯誤情況
setMode('editing');
// 如果這裡出錯,mode 已經改變但 value 沒有載入
setValue(committedValue);
無效操作沒有保護
// viewing 狀態下誤觸 textChange
textChange('new value'); // 沒有檢查 mode,直接修改了 value
// editing 狀態下誤觸 textEditStart
textEditStart(); // 可能導致資料丟失
邏輯散落各處
除錯困難
// 出現 bug 時很難回答這些問題:
// - 在什麼狀態下發生的?
// - 允許的狀態轉換有哪些?
// - 是誰觸發了這個狀態變化?
如果我們改成這樣:
const textMachine = {
context: { value: '', committedValue: '' },
initial: 'viewing',
states: {
viewing: {
on: {
EDIT_START: {
target: 'editing',
actions: {
value: ({ context }) => context.committedValue
}
}
}
},
editing: {
on: {
TEXT_CHANGE: {
actions: {
value: (_, event) => event.value
}
},
TEXT_COMMIT: {
actions: {
committedValue: ({ context }) => context.value
},
target: 'viewing'
},
TEXT_CANCEL: {
actions: {
value: ({ context }) => context.committedValue
},
target: 'viewing'
}
}
}
}
}
層面 | 傳統做法 | XState 狀態機 |
---|---|---|
程式碼量 | 較少,直觀簡潔 | 較多,結構化樣板代碼 |
學習成本 | 低,React 原生概念 | 中等,需要理解狀態機概念 |
錯誤預防 | 依賴開發者手動檢查 | 設計層面就避免無效操作 |
狀態一致性 | 容易出現不一致 | 強制保證狀態一致性 |
邏輯集中性 | 分散在各個函數 | 集中在狀態機定義中 |
可視化 | 需要閱讀程式碼理解 | 可直接產生狀態圖 |
除錯難度 | 需要追蹤多個變數 | 明確的狀態和轉換歷史 |
擴展性 | 隨複雜度增加而困難 | 結構化,容易擴展新狀態 |
const textChange = (newValue) => {
// 每次操作都要檢查是否允許
if (mode !== 'editing') {
console.warn('只能在編輯模式下修改文字');
return;
}
setValue(newValue);
}
editing: {
on: {
TEXT_CHANGE: { /* 只有在 editing 狀態才會處理 */ }
// EDIT_START 事件會被忽略,因為沒有定義
}
}
XState 帶來狀態管理新視角,從情境去看操作而不是在操作中檢查。
相比之下,雖然有更多的樣板代碼與 Redux 相似,但唯一差異是這些操作只會在某個情境下觸發,從根本上減少發生 bug 的可能性。
這種**「設計先行」**的思維模式,讓我們在寫程式碼之前就能:
最終實現**「預防勝於治療」**的開發理念,將原本不可控的除錯時間,轉換為可控的設計時間。
「與其花時間除錯,不如花時間設計」- 這就是 XState 狀態機帶給我們的核心價值。