实例化Element.type为function的 挂载实例的方法 --- updateComponent

272 阅读3分钟

updateComponent

updateComponent方法是综合组件挂载实例的核心方法之一,主要的作用是在组件更新的时候调用。

方法的代码如下所示:

    updateComponent: function (transaction, prevParentElement, nextParentElement, prevUnmaskedContext, nextUnmaskedContext) {
        
        '
            取出来组件实例,这个属性在 mountComponent方法被调用的时候组件实例化的时候赋值。
        '
        var inst = this._instance;
        
        '
            拿到上下文环境
        '
        var nextContext = this._context === nextUnmaskedContext ? inst.context : this._processContext(nextUnmaskedContext);
        
        '
            定义要更新使用的props
        '
        var nextProps;
    
        '
            这里计算出 nextProps。如果只是修改了state,也就是 prevParentElement === nextParentElement为true的时候。为nextProps赋值 nextParentElement.props;
            
            这里主要是用来 区分 props 更新和 一个简单的 state更新。
            prevParentElement === nextParentElement为truw是 state更新。只更新state。
            
        '
        if (prevParentElement === nextParentElement) {
          
          
          nextProps = nextParentElement.props;
        } else {
            '
                如果是props更新,就处理得到nextProps
            '
          nextProps = this._processProps(nextParentElement.props);
            '
                如果组件定义的有 componentWillReceiveProps方法的话就执行。
                一般这个方法就是在props被改变的时候执行。这里要注意父组件的state改变也会造成 子组件的 props的修改。
            '
          if (inst.componentWillReceiveProps) {
            inst.componentWillReceiveProps(nextProps, nextContext);
          }
        }
        
        '
            这里综合处理state
        '
        var nextState = this._processPendingState(nextProps, nextContext);
        
        '
            决定是否更新this._pendingForceUpdate 表示手动的强制更新。
            !inst.shouldComponentUpdate 表示组件实例不存在 shouldComponentUpdate 方法,
            inst.shouldComponentUpdate(nextProps, nextState, nextContext); 计算是否需要更新。
            
        '
        var shouldUpdate = this._pendingForceUpdate || !inst.shouldComponentUpdate || inst.shouldComponentUpdate(nextProps, nextState, nextContext);
        
        
        if (shouldUpdate) {
            '
                如果需要更新
            '
          this._pendingForceUpdate = false;
          '
            调用_performComponentUpdate方法更新组件。关于 _performComponentUpdate 方法往下看。
          '
          this._performComponentUpdate(nextParentElement, nextProps, nextState, nextContext, transaction, nextUnmaskedContext);
        } else {
          this._currentElement = nextParentElement;
          this._context = nextUnmaskedContext;
          inst.props = nextProps;
          inst.state = nextState;
          inst.context = nextContext;
        }
    }

_processProps

该方法就是在非正式环境下,根据提供的propTypes来验证props。

    _processProps: function (newProps) {
        if (process.env.NODE_ENV !== 'production') {
          var Component = this._currentElement.type;
          if (Component.propTypes) {
            this._checkPropTypes(Component.propTypes, newProps, ReactPropTypeLocations.prop);
          }
        }
        return newProps;
    },

shouldComponentUpdate

这里来说一下 shouldComponentUpdate 方法,这个是React赋予开发者的方法,开发者可以收到的使用这个方法来决定组件是否需要更新。类似于生命周期。

因为这个方法的存在,可以有效的提升React的性能,避免不必要的渲染。

_performComponentUpdate

    _performComponentUpdate: function (nextElement, nextProps, nextState, nextContext, transaction, unmaskedContext) {
        '
            拿到组件实例
        '
        var inst = this._instance;
        '
            计算组件有没有 生命周期函数 componentDidUpdate
        '
        var hasComponentDidUpdate = Boolean(inst.componentDidUpdate);
        var prevProps;
        var prevState;
        var prevContext;
        '
            如果组件定义的有生命周期函数 componentDidUpdate的话,就先保存好志气的props,state等,留待后用。
        '
        if (hasComponentDidUpdate) {
          prevProps = inst.props;
          prevState = inst.state;
          prevContext = inst.context;
        }
        '
            生命周期函数 componentWillUpdate 在这个地方使用。
        '
        if (inst.componentWillUpdate) {
          inst.componentWillUpdate(nextProps, nextState, nextContext);
        }
        
        '
            将当前要更新的组件信息替换,老旧的信息
        '
        this._currentElement = nextElement;
        this._context = unmaskedContext;
        inst.props = nextProps;
        inst.state = nextState;
        inst.context = nextContext;
        
        '
            调用 _updateRenderedComponent 方法更新,往下看 _updateRenderedComponent 方法
        '
        this._updateRenderedComponent(transaction, unmaskedContext);
        
        '
            如果有 ComponentDidUpdate组件生命周期方法,就执行。
        '
        if (hasComponentDidUpdate) {
          transaction.getReactMountReady().enqueue(inst.componentDidUpdate.bind(inst, prevProps, prevState, prevContext), inst);
        }
      },

_updateRenderedComponent

    _updateRenderedComponent: function (transaction, context) {
        '
            _renderedComponent 存储的是当前挂载实例的属性,其值为组件render方法返回的element 的挂载实例。
        '
        var prevComponentInstance = this._renderedComponent;
        
        '
            _currentElement 是当前挂载组件实例的 Element 表示形式。
        '
        var prevRenderedElement = prevComponentInstance._currentElement;
        '
            _renderValidatedComponent 方法最终会调用当前组件的 render方法来返回一个Element。
        '
        var nextRenderedElement = this._renderValidatedComponent();
        
        '
            shouldUpdateReactComponent 方法证明是直接更新组件,还是直接卸载旧组件而后挂载新组件。
            为true,表示组件只是修改部分props或者是state。为false表示,新组件与旧组件已经完全不一样了。
        '
        if (shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement)) {
            '
                ReactReconciler.receiveComponent 方法会递归组件内部所有的挂载实例的receiveComponent方法,对组件进行更新。直到最后调用 ReactDOMComponent类型的挂载实例的reveiveComponent方法。更新每一个 ReactDOMComponent 类型的实例。
                
                组件归根结底是由  ReactDOMComponent类型的实例组成的。这些实例更新完成,整个组件也就更新完成了。
             '
            ReactReconciler.receiveComponent(prevComponentInstance, nextRenderedElement, transaction, this._processChildContext(context));
         
        } else {
        
            '
                这一部分是,不更新组件,而是选择卸载旧组件,而后将新组件直接当做新组件进行挂载。
            '
          var thisID = this._rootNodeID;
          var prevComponentID = prevComponentInstance._rootNodeID;
          ReactReconciler.unmountComponent(prevComponentInstance);
    
          this._renderedComponent = this._instantiateReactComponent(nextRenderedElement);
          var nextMarkup = ReactReconciler.mountComponent(this._renderedComponent, thisID, transaction, this._processChildContext(context));
          this._replaceNodeWithMarkupByID(prevComponentID, nextMarkup);
        }
    },

总结

综合组件的挂载实例的 updateComponent 方法,负责综合组件的更新。 综合组件中包含了 类似HTML的DOM组件和纯文本的TextDOM组件,以及同样是综合组件的自定义组件。React会将一个组件的内容(child)全部转换为 DOM组件或者是TextDOM组件而后更新。