-
Notifications
You must be signed in to change notification settings - Fork 324
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MobX 原理 #3
Comments
勘个误:
这里应该是 段落标题 |
写的很清楚,很感谢~~! 不清楚的地方都明白了。 |
写的很好 :) |
bar.set(10); 会触发 autorun,输出foo 0 吧?? |
好文 感谢🙏 |
我一直就想了解mobx原理,由于不是前端出生让我学习起来比较困难,浅显易懂,感谢分享。 |
虽然没明白 但还是给个赞 |
触发autorun那里为什么会有diff?diff的意义在哪里?应该是直接拿第二次的依赖覆盖第一次就可以了。不然第三步foo.set(100)会执行autorun。 |
@anysome bar.set(10); 不触发 autoRun 的原因是,mobx 依赖追踪是动态的,这个时候还没有与 bar 建立关联,只改 bar 当然是不会触发的。 @JanzenZhangChen 这里的 diff 指的是啥我也没看太明白,不过触发 autoRun 之前是有个对比,如果对象修改后的值与修改前的相同,那就不触发 autoRun 了。 |
感谢🙏 |
一直在改变状态也不触发autorun,原来我一直在autorun里面console.log一堆字符串,现在看了文章,感觉这个计算依赖太神奇了,我完全没想到能有那么magic的方法 |
|
@xulayen 贴代码..... |
import React, { Component } from 'react';
import { observable } from 'mobx';
import { observer } from 'mobx-react';
const appState = observable({
count: 50,
});
appState.increment = function() {
this.count ++;
console.log(appState.count)
};
appState.decrement = function() {
this.count --;
console.log(appState.count)
};
@observer
class App extends Component {
constructor(props){
super(props);
}
handleInc() {
appState.increment();
}
handleDec() {
appState.decrement();
}
render() {
return (
<div className="App">
<div>
Counter: { appState.count } <br />
<button onClick={this.handleInc}>点击 + 加</button>
<button onClick={this.handleDec}>点击 - 减</button>
</div>
</div>
);
}
}
export default App; |
应该是 transaction 吧 |
在 observing 的 Observable 的 observer 里添加这个 Derivation |
先来看一个典型的 mobx + react 例子。(在 jsfiddle 里打开)
这个例子里,先通过 mobx 定义了 appState,Count 的 render 执行时里引用 appState 的数据。然后如果用户点击 + 或 - 按钮,会触发 appState 的修改,appState 的修改会自动触发 Counter 的更新。
基本原理
而要理解 mobx 的原理,我们需要一个更底层的例子。
运行结果是:
大家可能会好奇,为什么
counter.set()
之后,autorun
会自动执行? 要达到这个目的,通过counter
需要知道autorun
是依赖他的。那么这个依赖关系是在什么时候以及如何生成的呢?先看代码,这里涉及了 mobx 的 observable 和 autorun 接口。与此相关的有 Observable 和 Derivation 两个类。Observable 是数据源,Derivation 是推导。
类定义如下:
然后,
autorun
执行的步骤是这样的:到这里,Observable 和 Derivation 的依赖关联就建立起来了。
那么
counter.set()
执行之后是如何触发autorun
自动执行? 在有了上面这一层依赖关系之后,这个就很好理解了。counter.set()
执行时会从自己的 observing 属性里取依赖他的 Derivation,并触发他们的重新执行。运行时依赖计算
再看一个例子。
执行结果:
autorun 先是依赖 counter 和 foo,然后 counter 设为 1 之后,就不依赖 foo,而是依赖 counter 和 bar 了。所以之后修改 foo 并不会触发 autorun 。
那么 mobx 是如何在运行时计算依赖的呢?
实际上前面的
autorun
的执行步骤是做了简化的,真实的是这样:(+)
(+)
相比之前的,增加了 diff 的逻辑,以达到每次执行的时候动态更新依赖关系表的目的。
get/set magic
大家在看前面的例子里可能会有个疑问,为啥第一个例子里可以通过
appState.counter
来设置,而后面的例子里需要用counter.get
和counter.set
来取值和设值?这和数据类型有关,mobx 支持的类型有 primitives, arrays, classes 和 objects 。primitives (原始类型) 只能通过 set 和 get 方法取值和设值。而 Object 则可以利用
Object.defineProperty
方法自定义 getter 和 setter 。详见源码。
ComputedValue
ComputedValue 同时实现了 Observable 和 Derivation 的接口,即可以监听 Observable,也可以被 Derivation 监听。
Reaction
Reaction 本质上是 Derivation,但他不能再被其他 Derivation 监听。
Autorun
autorun 是 Reaction 的简单封装。
同步执行
其他的 TFRP 类库,比如 Tracker 和 Knockout ,数据更新后的执行都是异步的,需要等到下一个 event loop 。(可以想象成 setTimeout)
而 Mobx 的执行是同步的,这样做有两个好处:
Transation
由于 mobx 的更新是同步的,所以每 set 一个值,就会触发 reaction 的更新。所以为了批量更新,就引入了 transation 。
在一些情况下,等所有的修改执行完再执行所有的 deviration 会更合适。注意 transaction 只是推迟了 deviration 的执行,本身还是同步的。
Action
action 是 transation 是简单封装,支持通过 decorator 的方式调用。并且是
untrack
的,这样可以在 Derivation 里调用他。Observe (mobx-react)
第一次 render 时:
有数据修改时:
shouldComponentUpdate:
componentWillReact:
总结
第一眼看 mobx 觉得非常简单,概念也少。这对于简单项目可能够了,但在项目复杂之后就需要用到一些高级的功能,从而需要接触很多的概念,比如 Observable, ComputedValue, Derivation, Action, Transation, Autorun, Reaction, Modifier 等等。其实一点都不比 redux 简单。。
个人很喜欢 mobx 这个库,里面包含很多非常巧妙的实现和优化。所以试着想把原理给讲明白,但写完之后发现还是有些晦涩。
参考
The text was updated successfully, but these errors were encountered: