MobX會對在任何一個被監控的function執行的過程當中被讀取的已經存在的observable的屬性進行反應。
上面的這句話裏面有幾個關鍵的點:
1:正在被讀取
正在讀取的意思是:取用一個對象的屬性。例如:user.name或者user['name']
2:可被監控的function
可被監控的function是computed的一個表述,有如下幾種狀況:react
1:一個observer的組件的render()方法 2:做爲第一個參數傳給when(), reaction()和autorun()的function
3:在...過程當中
在...過程當中,意思是隻有在方法的執行中被讀取的observable才被track了。這些observable是被直接的仍是間接地被使用,並不影響。數組
換句話說,MboX不會對如下狀況進行反應:
1:從一個observable讀取的值,可是沒有被用在一個可被監控的function裏面
2:在一個異步調用的代碼塊裏被讀取的變量異步
一:MobX監控屬性的讀取,而不是屬性的值
咱們如下面的一段代碼示例來解釋上面的這條規則是設麼意思:spa
let message = observable({ title: "Foo", author: { name: "Michel" }, likes: ["John", "Sara"] })
在內存裏面它看起來以下圖所示。綠色的模塊表示是observable的屬性。注意,這些數值自己不是observable的!code
如今基本上,MobX作的事情就是記錄在你的function裏面,你使用的是哪一個箭頭。在那以後,不論哪一個箭頭髮生變化,他都會從新運行。也就是當這些箭頭指向一個其餘的值。server
Examples
咱們基於上面的message這個observable。對象
正確:在一個被監控的方法裏面讀取一個屬性:blog
autorun(()=>{ console.log(message.title) }) message.title = 'Bar'
以上代碼會如咱們期待的那樣。由於.title是在autorun裏面被讀取,且以後改變了,因此這個改變會被識別到。內存
不正確:修改一個不是observable的referenceit
autorun(() => { console.log(message.title) }) message = observable({ title: "Bar" })
上面的代碼不會反應。由於雖然message改變了,可是message不是一個observable,而僅僅是一個指向一個observable的變量,而這個變量(這個reference)它本身不是一個observable。
不正確:在一個監控方法外讀取屬性
var title = message.title autorun(() => { console.log(title) }) message.title = "Bar"
這段代碼也不會反應,由於message.title是在監控方法外被讀取,於是它只是包含message.title的值(也就是'Foo')。因此,title不是一個observable,因此autorun不會反應。
正確: 在一個監控方法內部讀取屬性
autorun(() => { console.log(message.author.name) }) message.author.name = "Sara" message.author = { name: "John" }
以上代碼的最後2行代碼都會致使MboX反應。由於.author和.author.name都在一個autorun裏面被引用,這就容許MboX去跟蹤這些references。
不正確:給一個observable存儲了一個沒有被跟蹤的本地變量
const author = message.author autorun(() => { console.log(author.name) }) message.author.name = "Sara" message.author = { name: "John" }
上面的代碼,倒數第一行不會觸發MobX反應,而倒數第二行會。由於,在autorun裏面只獲取了author.name,而message.author沒有在autorun裏面被使用,因此message.author的變化沒有被跟蹤,在autorun裏面使用的仍是老的author。
接下來咱們要看Array了。Array的狀況與Object有一些區別。
如下的例子,依然基於如下的代碼:
let message = observable({ title: "Foo", author: { name: "Michel" }, likes: ["John", "Sara"] })
正確:在一個被監控的方法裏讀取Array的屬性
autorun(() => { console.log(message.likes.length) }) message.likes.push("Jennifer")
以上的代碼會按照咱們期待的那樣執行。.length是Array的一個屬性。注意:上面的代碼會對array的任何改變都做出反應。Array是檢測它的所有,而不是像map或者對象那樣監控每個鍵值對。例如:
autorun(() => { console.log(message.likes[0]) }) message.likes.push("Jennifer")
以上的這段代碼,新增長了一個元素,使得Array自己改變了,因此會致使autorun裏面的代碼會被從新執行一遍。Array的下標被當作屬性被訪問,可是隻有當下標沒有越界的狀況下才有效。Mobx不會監控還不存在的下標或者對象的屬性(除非是用map)。
不正確:在被監控的方法裏訪問越界的元素
autorun(() => { console.log(message.likes.join(", ")) }) message.likes[2] = "Jennifer"
以上的代碼不會成功。由於訪問了越界的下標。
正確: 在監控方法裏面訪問Array的方法
autorun(() => { console.log(message.likes.join(", ")) }) message.likes.push("Jennifer")
以上代碼會按照指望的觸發autorun的執行。Array全部的沒有修改原Array的方法,都會被自動監控。
不正確:使用了observable,可是沒有讀取它的任何屬性
autorun(() => { message.likes }) message.likes.push("Jennifer")
以上的代碼不會使得autorun在執行。由於,likes數組本身自己沒有被autorun使用,而是likes數組的reference被autorun使用了。