mobx-react 源码阅读笔记(一)

前言

emm 由于实习的项目组只有自己一个人,选型开发都为所欲为了tat,从以redux进行数据流管理的使用,决定尝试一波实战mobx,在使用中不禁在想,mobx是怎么和react连在一起,而mobx又是为什么可以如此高效便捷。react-redux的驱动视图更新是通过connect组件,在外层HOC中订阅store改变触发
setState({})进行更新视图。而mobx-react中的observer呢?

这里可以看到最关键的一点,区别于redux的更新方式,在mobx-react中是直接使用forceUpdate方法进行更新视图,而区别于redux 对store的订阅,mobx-react又是怎么样触发forceUpdate呢?

/**
 *强制更新组件https://github.com/mobxjs/mobx-react/blob/master/src/observer.js#L188
 */
Component.prototype.forceUpdate.call(this)

定位到observer,先了解observer执行的流程


1.png

核心点


2.png

talk is so cheap show you the code

//... 
// https://github.com/mobxjs/mobx-react/blob/master/src/observer.js#L334
mixinLifecycleEvents(target)
//mixin组件的生命周期,将reactiveMixin中的函数mixin到具体的生命周期中.

在mixin中最核心需要关注的就是componentWillMount,
先简单提一下mixinLifecycleEvents区别对待的是shouldComponentUpdate,如果该方法没有定义observer会直接将其重写为PureComponentshouldComponentUpdate的实现

进一步看componentWillMount

//https://github.com/mobxjs/mobx-react/blob/master/src/observer.js#L168
// wire up reactive render
        //保存当前函数的render
        const baseRender = this.render.bind(this)
        let reaction = null
        let isRenderingPending = false

        const initialRender = () => {
            /*绑定reaction,observable属性改变的时候会触发这个(mobx实质是双向绑定,observable更新视图也要更新,这里是数据绑定到视图上的第一步。)
            */
            reaction = new Reaction(`${initialName}#${rootNodeID}.render()`, () => {
                if (!isRenderingPending) {
                    // N.B. Getting here *before mounting* means that a component constructor has side effects (see the relevant test in misc.js)
                    // This unidiomatic React usage but React will correctly warn about this so we continue as usual
                    // See #85 / Pull #44
                    isRenderingPending = true
                    if (typeof this.componentWillReact === "function") this.componentWillReact() // TODO: wrap in action?
                    if (this.__$mobxIsUnmounted !== true) {
                        // If we are unmounted at this point, componentWillReact() had a side effect causing the component to unmounted
                        // TODO: remove this check? Then react will properly warn about the fact that this should not happen? See #73
                        // However, people also claim this migth happen during unit tests..
                        let hasError = true
                        try {
                            isForcingUpdate = true
                            if (!skipRender) Component.prototype.forceUpdate.call(this)
                            hasError = false
                        } finally {
                            isForcingUpdate = false
                            if (hasError) reaction.dispose()
                        }
                    }
                }
            })
            reaction.reactComponent = this
            reactiveRender.$mobx = reaction
            // 重写render
            this.render = reactiveRender
            // 实际的render
            return reactiveRender()
        }
        
        const reactiveRender = () => {
            isRenderingPending = false
            let exception = undefined
            let rendering = undefined
            /**
            * 核心关联部分
            * 追踪数据  
            * https://github.com/mobxjs/mobx/blob/master/src/core/reaction.ts#L112
            * reaction.track(fn: () => void)
            * 实际上
            * trackDerivedFunction(derivation: IDerivation, f: () => T, context)
            * const result = trackDerivedFunction(this, fn, undefined)// this对应reaction,fn对应track中的fn
            *   (https://github.com/mobxjs/mobx/blob/master/src/core/derivation.ts#L131)
            * trackDerivedFunction这个函数有什么作用? 
            * 执行函数f并跟踪那些可观察并且正在f函数中引用的变量,将这些可追踪的变量注册并储存在derivation中即reaction中
            * 
            * f中引用的变量 核心上是通过atom.reportObserved()关联引用
            * 简单例子见   makePropertyObservableReference  中的      
            *       get: function() {
            *        atom.reportObserved() 
            *        return valueHolder
            *    },
            * 
            *  重新到trackDerivedFunction执行中
            * result = f.call(context); 
            *f本身已经是箭头函数了,上下文已经绑定过了. 这里实际上就是执行component的render,
            *实际上就是通过这里收集到observable的引用 (依赖收集)
            *trackDerivedFunction中会derivation进行属性更新,以及通过bindDependencies更新依赖收集的情况。
            **/
            reaction.track(() => {
                if (isDevtoolsEnabled) {
                    this.__$mobRenderStart = Date.now()
                }
                try {
                    rendering = extras.allowStateChanges(false, baseRender)
                } catch (e) {
                    exception = e
                }
                if (isDevtoolsEnabled) {
                    this.__$mobRenderEnd = Date.now()
                }
            })
            if (exception) {
                errorsReporter.emit(exception)
                throw exception
            }
            return rendering
        }

        this.render = initialRender
    },

这一次的阅读之行到此就暂告一段落了,关于derivation原理的进一步理解需要进一步学习mobx的源码。目前只是有较浅的理解,如有不正之处,请大家指出! tat 毕竟只是闭门造车。


注释版源码

学习资料

  • http://www.cnblogs.com/rubylouvre/p/6058575.html
  • https://zhuanlan.zhihu.com/p/27448262

你可能感兴趣的:(mobx-react 源码阅读笔记(一))