在上一部分中,我們研究瞭如何設定MobX狀態樹並使其可觀察。 有了這個,下一步就是開始對變化作出反應。 坦率地說,這就是有趣的開始!
MobX保證只要您的響應資料圖發生變化,依賴於可觀察屬性的部分就會自動同步。 這意味著您現在可以專注於對變化做出反應並引起的副作用,而不是擔心資料同步。
讓我們深入研究一下可以引起副作用的各種方法。
使用@action
作為入口點
預設情況下,當您修改observable時,MobX將檢測並保持其他依賴的可觀察物件同步。 這是同步發生的。 但是,有時您可能希望在同一方法中修改多個observable。 這可能會導致多個通知被觸發,甚至可能會降低您的應用速度。
更好的方法是action()
中包裝要呼叫的方法。 這會在您的方法周圍建立一個事務邊界,並且所有受影響的observable
將在您執行操作後保持同步。 請注意,此延遲通知僅適用於當前函式範圍中的observable
。 如果您具有修改更多可觀察物件的非同步操作,則必須將它們包裝在runInAction()
中。
class Person {
@observable firstName;
@observable lastName;
// 因為我們在@action中包裝了此方法,所以只有在changeName()成功執行後,fullName才會更改
@action changeName(first, last) {
this.firstName = first;
this.lastName = last;
}
@computed get fullName() {
return `${this.firstName}, ${this.lastName}`;
}
}
const p = new Person();
p.changeName('Pavan', 'Podila');
Actions
是改變Store的切入點。 通過使用Actions
,您可以將多個observable更新為原子操作。
儘可能避免直接從外部操縱observable
並公開@action
方法為你做這個改變。 實際上,可以通過設定useStrict(true)
來強制執行此操作。
使用@autorun
觸發副作用
MobX確保可觀察圖形始終保持一致。 但如果這個世界只是關於可觀察的東西,那就不好玩了。 我們需要他們的同行:觀察者使事情變得有趣。
實際上,UI是mobx store
的美化觀察者。 使用mobx-react
,您將獲得一個繫結庫,使您的React元件可以觀察儲存並在儲存更改時自動呈現。
但是,UI不是系統中唯一的觀察者。 您可以向store
新增更多觀察者以執行各種有趣的事情。 一個非常基本的觀察者可能是一個控制檯記錄器,它只是在可觀察的變化時將當前值記錄到控制檯。
通過autorun
,我們可以非常輕鬆地設定這些觀察者。 最快的方法是提供autorun
功能。 MobX會自動跟蹤您在此函式中使用的任何可觀察物件。 每當它們改變時,你的功能都會重新執行(也就是自動執行)!
class Person {
@observable firstName = 'None';
@observable lastName = 'None';
constructor() {
// A simple console-logger
autorun(()=>{
console.log(`Name changed: ${this.firstName}, ${this.lastName}`);
});
// 這裡會導致autorun()執行
this.firstName = 'Mob';
// autorun()再一次執行
this.lastName = 'X';
}
}
// Will log: Name changed: None, None
// Will log: Name changed: Mob, None
// Will log: Name changed: Mob, X
正如您在上面的日誌中所看到的,自動執行將立即執行,並且每次跟蹤的可觀察量發生變化時也會執行。 如果您不想立即執行,而是僅在發生更改時執行,該怎麼辦? 請繼續閱讀。
首次更換後使用reaction
觸發副作用
與autorun
相比,reaction
提供了更細粒度的控制。 首先,它們不會立即執行並等待對跟蹤的可觀察量的第一次更改。 API也與autorun
略有不同。 在最簡單的版本中,您提供兩個輸入引數:
reaction(()=> data, data => { /* side effect */})
第一個函式(跟蹤函式 tracking function
)應該返回將用於跟蹤的資料。 然後將該資料傳遞給第二個函式(效果函式 effect function
)。 不跟蹤效果函式,您可以在此處使用其他可觀察物件。
預設情況下,reaction
將不會在第一次執行,並將等待追蹤函式的變更。 只有當tracking function
返回的資料發生變化時,才會執行副作用。 通過將原始自動執行分解為tracking function
+effect function
,您可以更好地控制實際導致副作用的內容。
import {reaction} from 'mobx';
class Router {
@observable page = 'main';
setupNavigation() {
reaction(()=>this.page, (page)=>{
switch(page) {
case 'main':
this.navigateToUrl('/');
break;
case 'profile':
this.navigateToUrl('/profile');
break;
case 'admin':
this.navigateToUrl('/admin');
break;
}
});
}
navigateToUrl(url) { /* ... */ }
}
在上面的示例中,我在載入“main”頁面時不需要導航。 一個reaction
使用的完美案例。 僅當路由器的頁面屬性發生更改時,才會導航到特定URL。
以上是一個非常簡單的路由器,具有固定的頁面集。 您可以通過向URL新增頁面地圖來使其更具可擴充套件性。 使用這種方法,路由(使用URL更改)會成為更改Store某些屬性的副作用。
使用when
觸發一次性的副作用
autorun
和reaction
是持續的副作用。 初始化應用程式時,您將建立此類副作用,並期望它們在應用程式的生命週期內執行。
我之前沒有提到的一件事是這兩個函式都返回一個處理器函式。 您可以隨時呼叫該處理器函式並取消副作用。
const disposer = autorun(()=>{
/* side-effects based on tracked observables */
});
// .... At a later time
disposer(); // Cancel the autorun
現在我們構建的應用程式有各種用例。 您可能希望某些副作用僅在您到達應用程式中的某個點時執行。 此外,您可能希望這些副作用只執行一次,然後再也不會執行。
讓我們舉一個具體的例子:比如說,當使用者到達應用程式中的某個里程碑時,您希望向使用者顯示一條訊息。 此里程碑僅對任何使用者發生一次,因此您不希望設定持續執行的副作用,如autorun
或reaction
。 現在是時候拿出when
這個API來完成這項工作了。
當拿出兩個引數時,就像reaction
一樣。 第一個(跟蹤器函式)應該返回一個布林值。 當這變為真時,它將執行效果函式,第二個引數為when
。 最棒的部分是它會在執行後自動處理副作用。 因此,無需跟蹤處理器並手動呼叫它。
when(()=>this.reachedMilestone, ()=>{
this.showMessage({
title: 'Congratulations',
message: 'You did it!'
});
})
到目前為止,我們已經看到了各種技術來跟蹤物件圖上的變化,並對這些變化做出反應。 MobX提高了抽象級別,以便我們可以在更高階別進行思考,而不必擔心跟蹤和對變化做出反應的意外複雜性。
我們現在有了一個基礎,可以構建依賴於域模型更改的強大系統。 通過將域模型之外的所有內容視為副作用,我們可以提供視覺反饋(UI)並執行許多其他活動,如監控,分析,日誌記錄等。
- Part 1 - 構建可觀察資料
- Part 2 - 掌握資料變更方法
- Part 3 - 高階應用例項