MobX 的核心概念
概念
MobX 在您的應用程式中區分以下三個概念
- 狀態
- 動作
- 衍生
讓我們在下面仔細看看這些概念,或者,在 MobX 和 React 的 10 分鐘介紹 中,您可以逐步互動式地深入了解這些概念並構建一個簡單的待辦事項列表應用程式。
有些人可能會在下面描述的概念中認識到「信號」的概念。這是正確的,MobX 是一個基於信號的狀態管理庫 avant la lettre。
1. 定義狀態並使其可觀察
狀態是驅動您應用程式的資料。通常,存在特定領域的狀態,例如待辦事項列表,以及視圖狀態,例如當前選定的元素。狀態就像持有值的試算表儲存格。
將狀態儲存在您喜歡的任何資料結構中:純物件、陣列、類別、循環資料結構或參考。這對 MobX 的運作方式沒有影響。只要確保您想要隨著時間推移而更改的所有屬性都被標記為 observable
,以便 MobX 可以追蹤它們。
以下是一個簡單的範例
import { makeObservable, observable, action } from "mobx"
class Todo {
id = Math.random()
title = ""
finished = false
constructor(title) {
makeObservable(this, {
title: observable,
finished: observable,
toggle: action
})
this.title = title
}
toggle() {
this.finished = !this.finished
}
}
使用 observable
就像將物件的屬性變成試算表儲存格。但與試算表不同的是,這些值不僅可以是原始值,還可以是參考、物件和陣列。
提示:更喜歡類別、純物件或裝飾器?MobX 支援多種風格。
可以使用 makeAutoObservable
來縮短此範例,但透過明確說明,我們可以更詳細地展示不同的概念。請注意,MobX 並未規定物件風格,純物件也可以使用,裝飾器也可以用於更簡潔的類別。有關更多詳細資訊,請參閱該頁面。
但是我們標記為 action
的 toggle
呢?
2. 使用動作更新狀態
動作是任何更改狀態的程式碼片段。使用者事件、後端資料推送、排程事件等。動作就像使用者在試算表儲存格中輸入新值一樣。
在上面的 Todo
模型中,您可以看到我們有一個 toggle
方法可以更改 finished
的值。 finished
被標記為 observable
。建議您將任何更改 observable
的程式碼片段標記為 action
。這樣,MobX 可以自動應用事務,以輕鬆實現最佳效能。
使用動作可以幫助您建構程式碼,並防止您在不打算更改狀態時意外更改狀態。在 MobX 術語中,修改狀態的方法稱為*動作*。與*視圖*相反,視圖根據當前狀態計算新資訊。每個方法最多應服務於這兩個目標之一。
3. 建立自動響應狀態變化的衍生
任何可以從*狀態*衍生出來而無需任何進一步互動的東西都是衍生。衍生以多種形式存在
- 使用者介面
- 衍生資料,例如剩餘
todos
的數量 - 後端整合,例如將變更發送到伺服器
MobX 區分兩種衍生
- 計算值,始終可以使用純函數從當前可觀察狀態中衍生出來
- 反應,狀態改變時需要自動發生的副作用(命令式和反應式程式設計之間的橋樑)
開始使用 MobX 時,人們傾向於過度使用反應。黃金法則是,如果您想根據當前狀態建立值,請始終使用 computed
。
3.1. 使用計算值建模衍生值
要建立*計算值*,請使用 JS getter 函數 get
定義屬性,並使用 makeObservable
將其標記為 computed
。
import { makeObservable, observable, computed } from "mobx"
class TodoList {
todos = []
get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length
}
constructor(todos) {
makeObservable(this, {
todos: observable,
unfinishedTodoCount: computed
})
this.todos = todos
}
}
MobX 將確保在新增待辦事項或修改其中一個 finished
屬性時自動更新 unfinishedTodoCount
。
這些計算類似於 MS Excel 等試算表程式中的公式。它們會自動更新,但僅在需要時更新。也就是說,如果某些東西對它們的結果感興趣。
3.2. 使用反應建模副作用
為了讓您作為使用者能夠在螢幕上看到狀態或計算值的變化,需要一個重新繪製 GUI 部分的*反應*。
反應類似於計算值,但它們不是產生資訊,而是產生副作用,例如列印到控制台、發出網路請求、遞增更新 React 組件樹以修補 DOM 等。
簡而言之,反應將 反應式 和 命令式 程式設計的世界聯繫起來。
到目前為止,最常用的反應形式是 UI 組件。請注意,可以從動作和反應觸發副作用。具有明確、明確來源的副作用(例如在提交表單時發出網路請求)應從相關事件處理程式中明確觸發。
3.3. 反應式 React 組件
如果您使用的是 React,您可以透過使用您在 安裝過程中選擇 的繫結套件中的 observer
函數來包裝組件,使它們具有反應性。在此範例中,我們將使用更輕量級的 mobx-react-lite
套件。
import * as React from "react"
import { render } from "react-dom"
import { observer } from "mobx-react-lite"
const TodoListView = observer(({ todoList }) => (
<div>
<ul>
{todoList.todos.map(todo => (
<TodoView todo={todo} key={todo.id} />
))}
</ul>
Tasks left: {todoList.unfinishedTodoCount}
</div>
))
const TodoView = observer(({ todo }) => (
<li>
<input type="checkbox" checked={todo.finished} onClick={() => todo.toggle()} />
{todo.title}
</li>
))
const store = new TodoList([new Todo("Get Coffee"), new Todo("Write simpler code")])
render(<TodoListView todoList={store} />, document.getElementById("root"))
observer
將 React 組件轉換為它們所呈現資料的衍生。使用 MobX 時,沒有智慧或愚蠢的組件。所有組件都以智慧方式呈現,但以愚蠢的方式定義。MobX 只會確保組件始終在需要時重新呈現,並且絕不會超過此範圍。
因此,上述範例中的 onClick
處理程式將強制正確的 TodoView
組件重新呈現,因為它使用了 toggle
動作,但如果未完成任務的數量發生變化,則只會導致 TodoListView
組件重新呈現。如果您移除 `Tasks left` 行(或將其放入單獨的組件中),則 `TodoListView` 組件將不再在勾選任務時重新呈現。
要深入了解 React 如何與 MobX 配合使用,請查看 React 整合 部分。
3.4. 自定義反應
你很少會需要它們,但它們可以使用 autorun
、reaction
或 when
函式創建,以適應你的特定情況。例如,以下 autorun
會在每次 unfinishedTodoCount
的數量變化時印出一條日誌訊息
// A function that automatically observes the state.
autorun(() => {
console.log("Tasks left: " + todos.unfinishedTodoCount)
})
為什麼每次 unfinishedTodoCount
改變時都會印出新的訊息?答案是這個經驗法則
MobX 會對在追蹤函式執行期間讀取的任何現有可觀察屬性做出反應。
要了解更多關於 MobX 如何確定需要對哪些可觀察對象做出反應的資訊,請查看理解反應性章節。
原則
MobX 使用單向數據流,其中 _動作_ 改變 _狀態_,而 _狀態_ 又會更新所有受影響的 _視圖_。
當 _狀態_ 改變時,所有 _衍生值_ 都會 **自動** 且 **原子化地** 更新。因此,永遠不可能觀察到中間值。
默認情況下,所有 _衍生值_ 都會 **同步地** 更新。這意味著,例如,_動作_ 可以在更改 _狀態_ 後立即安全地檢查計算值。
_計算值_ 會 **延遲地** 更新。任何未被積極使用的計算值,直到副作用 (I/O) 需要它時才會更新。如果一個視圖不再被使用,它會被自動垃圾回收。
所有 _計算值_ 都應該是 **純粹的**。它們不應該改變 _狀態_。
要了解更多背景資訊,請查看 MobX 背後的基本原則。
試試看!
你可以在 CodeSandbox 上自行玩玩上述範例。
程式碼檢查(Linting)
如果你覺得難以適應 MobX 的心智模型,可以將它配置為非常嚴格,並在運行時只要你偏離這些模式就發出警告。請查看 MobX 程式碼檢查 章節。