高效能MobX模式(Part 1)
原文地址
// Mobx 3已經修改API了
MobX為管理客戶端狀態(state)提供了一套簡單並且強大的方法。它使用一種稱為
Transparent Functional Reactive Programming
(TFRP)的技術。如果一個值依賴於另一個值,那麼被依賴的值變化了,也會引起這個值的改變。這是透過建立依賴關係圖,它能夠追蹤依賴。
MobX能夠降低你的心智負擔,讓你重新思考怎樣管理一個客戶端的狀態(state)
我在用了它6個月後並且用它做了多個React的專案後,發現某些模式的使用的相當頻繁。這一系列的文章我將分享我在用MobX的過程中的心得
我打算分三部分分享,在第一部分,讓我們看看 MobX的 狀態樹長什麼樣子
Part 1 - Shaping the observables
Part 2 - Reacting to changesPart 3 - A Cookbook of use cases
開始用MobX的第一步可能就是要為你的客戶端建模了。這就像領域模型對映到你的應用上。從現在開始,我們將客戶端狀態稱為Store,當我說客戶端狀態的時候,其實我說的就是Store。要是以前用過Redux的話,你看能會熟悉這個概念。儘管你只有一個Store,但這個Store可以又多個子Store共同組成,然後一起處理你應用程式的各種功能。
最簡單的辦法就是在Store的屬性前面加一個 @observable,注意了啊,我用的是語法是註解(
decorator syntax
),如果你用的是ES5的話,你也可以用obserable 函式包裝一下。
import
{
observable
}
from
‘mobx’
;
class
AlbumStore
{
@
observable
name
;
@
observable
createdDate
;
@
observable
description
;
@
observable
author
;
@
observable
photos
=
[];
}
修剪observable
如果你在一個物件前面加了
@
observable
, 那麼他裡面所有巢狀的子屬性也會被置於
observe
下。上面這種情況是你大多數時候想要的結果,但是有的時候,你想只讓一部分
observe
下。你可以用 MobX modifiers做到這一點。
asReference()
如果是你知道一個物件,他裡面的值萬年不變而且永遠不會改變。這個方法非常有用了。注意了哈,如果我改變這個物件自身的引用,他還是會觸發改變通知的。比如說
let
address
=
new
Address
();
let
contact
=
observable
({
person
:
new
Person
(),
address
:
asReference
(
address
)
});
address
。
city
=
‘New York’
;
// No notifications won`t be fired
// Notifications will be fired as this is a reference change
contact
。
address
=
new
Address
();
上面這個例子,這個
address
裡面的屬性是不具備
observable
的。所以我改了裡面的內容,我是收不到改變通知的。然而我們改變
address
的引用,我們照舊會拿到改變通知
asFlat()
這個要比
asReference()
稍微寬鬆些,
asFlat
允許將自己的第一層子屬性置於
observe
下,這個最典型的用法就是用在陣列上,我只想觀察數組裡每一子項移入移除的變化,而不想知道每一子項內部的屬性如何變化的。在這種情況下,陣列的
length
改變我能不能觀察到啊?當然可以。
小提示:一個物件我們必須先是
observable
的,我們才能對他子屬性用
asReference
或者
asFlat
進行修剪。
如果你對你的
store
用深刻的理解,能夠確定哪些屬性不要深入
observable。
那麼這將對你的應用程式的效能提升有非常重要的意思
import
{
observable
}
from
‘mobx’
;
class
AlbumStore
{
@
observable
name
;
// No need to observe here
@
observable
createdDate
=
asReference
(
new
Date
());
@
observable
description
;
@
observable
author
;
// Only observing the photos array, not the individual photos
@
observable
photos
=
asFlat
([]);
}
擴充套件observable的能力
上面我們一直在說如何剪裁一個物件的
observable
的能力,那麼下面我們聊一聊如何擴充套件一個物件的
observable
的能力。
asStructure()
預設情況下只有引用的變化才會被認為是發生了變化。但是你希望你覺得內部結構的值變了才認為是發生了變話,那麼你可以用用它。他是建立在 type 和 value 基礎上的,他會比對type和value,如果他倆均沒發生改變,就認為它沒變
const
{
asStructure
,
observable
,
reaction
}
=
require
(
‘mobx’
)
let
address1
=
{
zip
:
12345
,
city
:
‘New York’
}
let
address2
=
{
zip
:
12345
,
city
:
‘New York’
}
let
contact
=
observable
({
address
:
address1
})
// Will be considered as a change, since its a new reference
contact
。
address
=
address2
// With asStructure() annotation
let
contact
=
observable
({
address
:
asStructure
(
address1
)
})
// Will NOT be considered as a change, since its the same value
contact
。
address
=
address2
asMap()
預設情況下,當你標記一個物件作為可觀察到的,它只能跟蹤到這個物件下面最開始定義的那些屬性。如果你在這個物件下再加一個新的屬性,那麼這個屬性是不會被追蹤到的。用
asMap
()就可以解決這個問題。
computed()
這個概念自己超級重要,怎麼強調都不過分。一個computed屬性並不是你領域模型裡面的屬性,而是根據你的領域模型計算出來的屬性。最典型的例子就是一個person例項的fullName是根據person例項的lastName和
firstName
計算出來的。它能夠幫助你減化你的領域模型的邏輯推理。舉個簡單的例子,你不必在用到檢查是否有lastName的地方都寫檢查邏輯,你只需要寫一個computed
hasLastName
的屬性就好了。程式碼如下
class
Person
{
@
observable
firstName
;
@
observable
lastName
;
@
computed
get
fullName
()
{
return
`
${
this
。
firstName
}
,
${
this
。
lastName
}
`
;
}
@
computed
get
hasLastName
()
{
return
!!
this
。
lastName
;
}
}
怎麼理解這張圖呢?帶加號的那兩個,是透過asMap新加的兩個屬性,另一個是computed的屬性。他們都被置於可觀察下
未完待續
在第二部分,我們來聊聊用當那些被置於可觀察下的值變化時,我們如何使用
@action。
來處理副作用