Mobx 提供 action API 供用户声明修改应用状态的函数。Mobx 进行了一层简单的包装,提供事务功能,可以在 action 内进行多次 Observable 的修改,而不用担心 Reaction 的多次重新执行;同时支持 spy,可以在开发工具中观察到 action 的执行。
action API 的入口如下:
1 | var action: IActionFactory = function action(arg1, arg2?, arg3?, arg4?): any { |
Action 原理
先来看 createAction 函数的实现:
1 | function createAction(actionName: string, fn: Function): Function & IAction { |
可见,只是返回了一个经过 executeAction 包装的函数。executeAction 在原函数的执行前后,分别调用了 startAction 和 endAction:
1 | function executeAction(actionName: string, fn: Function, scope?: any, args?: IArguments) { |
startAction 会先调用 untrackedStart 函数,将当前(可能有)正在跟踪的 Derivation 置为 null,避免依赖收集。然后调用 startBatch 开始一个新事务,确保 action 结束后才开始 Derivation 的重新计算。最后,将全局的标志位 allowStateChanges 置为 true。
1 | function startAction( |
action 执行完后,调用 endAction 还原两个全局变量,结束事务。
1 | function endAction(runInfo: IActionRunInfo) { |
作为装饰器使用
在 action 入口函数中会进入第三、四个分支,调用 namedActionDecorator 生成一个装饰器函数:
1 | function namedActionDecorator(name: string) { |
同样是使用 createClassPropertyDecorator 生成装饰器函数(参看第三篇):
1 | const actionFieldDecorator = createClassPropertyDecorator( |
这样在类实例化时,包装好的 action 就作为隐藏属性添加到了类实例上。
action.bound 绑定上下文
在 creatAction 函数中可以看到,action 使用默认的上下文:
1 | const res = function() { |
使用 action.bound 可以将 this 绑定到对象或类实例上:
1 | function defineBoundAction(target: any, propertyName: string, fn: Function) { |
runInAction
action(fn)() 的语法糖,直接调用了 executeAction:
1 | function runInAction<T>(arg1, arg2?, arg3?) { |