源码看React---- ref
                        ref是怎么引用到真实节点的<input type="text" ref={(node)=>{this.myInput = node}}/> 
这是我们在组件中书写的样式。我们知道,在HTML中这是个DOM节点,但是在React会经由jsx转化为 ReactElement.createElement = function(type,config,children) {
  var propName;
  // Reserved names are extracted
  var props = {};
  var key = null;
  var ref = null;
  var self = null;
  var source = null;
  if (config != null) {
    if (hasValidRef(config)) {
      ref = config.ref;
    }
    if (hasValidKey(config)) {
      key = '' + config.key;
    }
    ...
  return ReactElement(
    type,key,ref,self,source,ReactCurrentOwner.current,props,);
}; 
巴拉巴拉的细节逻辑就不看了,总之呢就是生成了一个ReactElement对象,而ref会保存为该对象的一个属性。 function instantiateReactComponent(node,shouldHaveDebugID) {
  var instance;
  console.log(node);
  if (node === null || node === false) {
    instance = ReactEmptyComponent.create(instantiateReactComponent);
  } else if (typeof node === 'object') {
    var element = node;
    var type = element.type;
    // Special case string values
    if (typeof element.type === 'string') {
      instance = ReactHostComponent.createInternalComponent(element);
    } else {
      instance = new ReactCompositeComponentWrapper(element);
    }
  } else if (typeof node === 'string' || typeof node === 'number') {
    instance = ReactHostComponent.createInstanceForText(node);
  }
  return instance;
} 
生成组件以后就会调用 mountComponent: function (internalInstance,transaction,hostParent,hostContainerInfo,context,parentDebugID) // 0 in production and for roots
  {
  //这里返回的markup就是渲染好的部分虚拟DOM树
    var markup = internalInstance.mountComponent(transaction,parentDebugID);
    if (internalInstance._currentElement && internalInstance._currentElement.ref != null) {
      transaction.getReactMountReady().enqueue(attachRefs,internalInstance);
    }
    return markup;
  }, 
从代码中可以看出,当ReactElement生成虚拟DOM节点以后,会进行判断,如果该节点有ref引用。则会把attachRefs函数和该节点传入回调函数序列。 transaction.getReactMountReady().enqueue(attachRefs,internalInstance); 这段代码里的transaction是 var SELECTION_RESTORATION = {
  /**
   * @return {Selection} Selection information.
   * 返回选中的信息
   */
  initialize: ReactInputSelection.getSelectionInformation,/**
   * @param {Selection} sel Selection information returned from `initialize`.
   */
  close: ReactInputSelection.restoreSelection,};
var EVENT_SUPPRESSION = {
  initialize: function() {
    //先确定当前是否可以进行事件处理。
    var currentlyEnabled = ReactBrowserEventEmitter.isEnabled();
    //防止此次事件处理过程中会发生其他transaction里面的事件
    ReactBrowserEventEmitter.setEnabled(false);
    return currentlyEnabled;
  },close: function(previouslyEnabled) {
    ReactBrowserEventEmitter.setEnabled(previouslyEnabled);
  },};
// 通过CallbackQueue回调函数队列机制,即this.reactMountReady
//    执行this.reactMountReady.enqueue(fn)注入componentDidMount、componentDidUpdate方法
// 通过Transaction添加前、后置钩子机制
//    前置钩子initialize方法用于清空回调队列;close用于触发回调函数componentDidMount、componentDidUpdate执行
var ON_DOM_READY_QUEUEING = {
  initialize: function() {
    this.reactMountReady.reset();
  },close: function() {
    this.reactMountReady.notifyAll();
  },};
var TRANSACTION_WRAPPERS = [
  SELECTION_RESTORATION,EVENT_SUPPRESSION,ON_DOM_READY_QUEUEING,];
var Mixin = {
  getTransactionWrappers: function() {
        return TRANSACTION_WRAPPERS;
    }
  } 
其中的 attachRefsref引用主要是ReactRef中的attachRef函数 //ref是我们标签中书写的ref
//component是书写ref的组件。上面提过,哪怕是input也会被封装成组件再挂载。
//owner是component所在的组件
function attachRef(ref,component,owner) {
  if (typeof ref === 'function') {
    ref(component.getPublicInstance());
  } else {
    // Legacy ref
    ReactOwner.addComponentAsRefTo(component,owner);
  }
} 
可以看到,正是在这边组件获取到了ref引用。 ref是function当ref时function时,函数的参数传入的是 
 这里不考虑空组件。主要是 getPublicInstance: function () {
    var inst = this._instance;
    return inst;
  }, 
直接传入了实例化对象。通过这个方法,我们可以通过ref随时调用子组件的内部方法。 getPublicInstance: function() {
    return getNode(this);
  },function getNodeFromInstance(inst) {
      if (inst._hostNode) {
        return inst._hostNode;
      }
    
      var parents = [];
    _prodInvariant('34') : void 0;
        inst = inst._hostParent;
      }
    
      for (; parents.length; inst = parents.pop()) {
        precacheChildNodes(inst,inst._hostNode);
      }
    
      return inst._hostNode;
    } 
这里是根据getNode获取的引用。getNode执行的又是 那么这个 el = ownerDocument.createElement(this._currentElement.type);
 ReactDOMComponentTree.precacheNode(this,el);
 
 //。。。。。我是分隔符
 
 function getRenderedHostOrTextFromComponent(component) {
  var rendered;
  while (rendered = component._renderedComponent) {
    component = rendered;
  }
  return component;
}
function precacheNode(inst,node) {
  var hostInst = getRenderedHostOrTextFromComponent(inst);
  hostInst._hostNode = node;
  node[internalInstanceKey] = hostInst;
} 
通过当前元素类型创造节点。接着将节点塞到了组件中,保存的正是 ref不是函数ref不是函数执行的是ReactOwner的 attachRef: function (ref,component) {
    var inst = this.getPublicInstance();
    var publicComponentInstance = component.getPublicInstance();
    var refs = inst.refs === emptyObject ? inst.refs = {} : inst.refs;
    refs[ref] = publicComponentInstance;
  }, 
而这里传入的component正是有ref属性的组件(前面说过,哪怕写在input上,挂载时也是包装成组件再挂载),此时的ReactOwner(this)是component所在的组件。 ref拿到的到底是什么很多文章里面说ref拿到的是真实DOM节点。其实这种说法很笼统。也很让人困惑,上面看到我们拿到的要么是实例(我们自定义组件)要么是component的_hostNode属性,这个好像不是真实DOM 啊 我们虽然是通过虚拟DOM的_hostNode拿到这个值,但是对他的操作会体现在真实DOM节点上。说白了就是对象的引用赋值。所以,ref拿到的是真实DOM的引用这个说法更准确。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!  | 
                  
