MobX会对在任何一个被监控的function执行的过程中被读取的已经存在的observable的属性进行反应。
上面的这句话里面有几个关键的点:
1:正在被读取
正在读取的意思是:取用一个对象的属性。例如:user.name或者user['name']
2:可被监控的function
可被监控的function是computed的一个表述,有以下几种情况:

1:一个observer的组件的render()方法
2:作为第一个参数传给when(), reaction()和autorun()的function

3:在...过程中
在...过程中,意思是只有在方法的执行中被读取的observable才被track了。这些observable是被直接的还是间接地被使用,并不影响。

换句话说,MboX不会对以下情况进行反应:
1:从一个observable读取的值,但是没有被用在一个可被监控的function里面
2:在一个异步调用的代码块里被读取的变量

一:MobX监控属性的读取,而不是属性的值
我们以下面的一段代码示例来解释上面的这条规则是设么意思:

let message = observable({
    title: "Foo",
    author: {
        name: "Michel"
    },
    likes: ["John", "Sara"]
})

在内存里面它看起来如下图所示。绿色的模块表示是observable的属性。注意,这些数值本身不是observable的!
Screen Shot 2019-11-15 at 7.23.26 PM.png

现在基本上,MobX做的事情就是记录在你的function里面,你使用的是哪个箭头。在那之后,不论哪个箭头发生变化,他都会重新运行。也就是当这些箭头指向一个其他的值。

Examples
我们基于上面的message这个observable。

正确:在一个被监控的方法里面读取一个属性:

autorun(()=>{
  console.log(message.title)
})
message.title = 'Bar'

以上代码会如我们期待的那样。因为.title是在autorun里面被读取,且之后改变了,所以这个改变会被识别到。

不正确:修改一个不是observable的reference

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使用了。


nanaistaken
586 声望43 粉丝