https://github.com/jimwmg/Rea...
1 React.createClass( )
<body> <div id="root"></div> <script type='text/babel'> var HelloWorld = React.createClass({ render : function(){ return <h1>hello {this.props.name1} <p>hello {this.props.name2}</p> </h1> } }) ; ReactDOM.render( <HelloWorld name1='Jhon' name2="JiM" />,document.getElementById('root') ) </script> </body>
2 React.Component
ES6的创建组件,其实根源还是调用了createClass
<div id="root"></div> <script type='text/babel'> class Welcome extends React.Component { render(){ return <h1>hello {this.props.name}</h1> } } const element = <Welcome name = 'JiM'/> ReactDOM.render( element,document.getElementById('root') ) </script>
编译之后
"use strict"; var _createClass = function () { function defineProperties(target,props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target,descriptor.key,descriptor); } } return function (Constructor,protoProps,staticProps) { if (protoProps) defineProperties(Constructor.prototype,protoProps); if (staticProps) defineProperties(Constructor,staticProps); return Constructor; }; }(); function _classCallCheck(instance,Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self,call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass,superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function,not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype,{ constructor: { value: subClass,enumerable: false,writable: true,configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass,superClass) : subClass.__proto__ = superClass; } var Welcome = function (_React$Component) { _inherits(Welcome,_React$Component); function Welcome() { _classCallCheck(this,Welcome); return _possibleConstructorReturn(this,(Welcome.__proto__ || Object.getPrototypeOf(Welcome)).apply(this,arguments)); } _createClass(Welcome,[{ key: "render",value: function render() { return React.createElement( "h1",null,"hello ",this.props.name ); } }]); return Welcome; }(React.Component);
3 function
import React from 'react' import { BrowserRouter as Router,Route,Link } from 'react-router-dom' const Repo = ()=>(<div>this is Repo</div>) const Category = (props)=>{ console.log(props); return (<div>this is category</div>) } const MyTest =()=>( <Router> <div> <ul> <li> <Link to='/about'>About</Link> </li> <li> <Link to='./repo'>Repo</Link> </li> <li> <Link to='./category'>Category</Link> </li> </ul> <Route exact path='/about' render={(props)=>{console.log(props);return (<div>this is aabout</div>) }}></Route> <Route exact path='/repo' component={Repo}> </Route> <Route exact path='/category' component={Category}> </Route> <Route children={(props)=>{console.log(props);return (<div>this is a component build througth children</div>) }}></Route> </div> </Router> ) export default MyTest
ES6一般写法
const BasicExample = () => ( <Router> <div> <ul> <li><Link to="/">Home</Link></li> <li><Link to="/about">About</Link></li> <li><Link to="/topics">Topics</Link></li> </ul> <hr/> <Route exact path="/" component={Home}/> <Route path="/about" component={About}/> <Route path="/topics" component={Topics}/> </div> </Router> )
tips:建议用webstorm来进行源码的跟踪链接;
4 React.js
从源码角度来看创建一个React组件的过程中发生了什么。
react.js源码github地址
var createReactClass = require('./createClass'); var React = { // Modern Children: { map: ReactChildren.map,forEach: ReactChildren.forEach,count: ReactChildren.count,toArray: ReactChildren.toArray,only: onlyChild },Component: ReactBaseClasses.Component,PureComponent: ReactBaseClasses.PureComponent,createElement: createElement,cloneElement: cloneElement,isValidElement: ReactElement.isValidElement,// Classic PropTypes: ReactPropTypes,createClass: createReactClass,createFactory: createFactory,createMixin: createMixin,// This looks DOM specific but these are actually isomorphic helpers // since they are just generating DOM strings. DOM: ReactDOMFactories,version: ReactVersion,// Deprecated hook for JSX spread,don't use this for anything. __spread: __spread };
看下React其实是个大的对象,对象上挂载了很多方法,当我们创建一个组件的时候,会调用createClass方法。
首先记住一点,无论是createClass还是class创建React组件,本质上都是一个函数,然后向组件(函数)prototype添加属性和方法;;
看下createClass.js源码
var _require = require('./ReactBaseClasses'),Component = _require.Component; var _require2 = require('./ReactElement'),isValidElement = _require2.isValidElement; var ReactNoopUpdateQueue = require('./ReactNoopUpdateQueue'); var factory = require('create-react-class/factory'); module.exports = factory(Component,isValidElement,ReactNoopUpdateQueue);
ReactBaseClasses源码地址:这里解释了组件上为何有forceUpdate,以及setState等接口;
ReactElement.js源码地址:这里解释了jsx转译之后,React到底是如何创建虚拟DOM对象的;
factory.js源码地址:这里解释了创建React组件(函数)的过程;
5 ReactDOM.js
接下来看下创建一个React组件之后,如何通过ReactDOM.render(element,container)将其加载到指定 的DOM节点的。以下只贴关键源码,其他的都附有源码地址,读者可自行查看;
ReactDOM.js源码地址
ReactDefaultInjection源码地址
源码解读
var ReactDefaultInjection = require('./ReactDefaultInjection'); ReactDefaultInjection.inject(); //上面两行是使ReactHostComponent.createInternalComponent注册方法; var ReactDOM = { findDOMNode: findDOMNode,render: ReactMount.render,unmountComponentAtNode: ReactMount.unmountComponentAtNode,/* eslint-disable camelcase */ unstable_batchedUpdates: ReactUpdates.batchedUpdates,unstable_renderSubtreeIntoContainer: renderSubtreeIntoContainer /* eslint-enable camelcase */ }; // Inject the runtime into a devtools global hook regardless of browser. // Allows for debugging when the hook is injected on the page. if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') { __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({ ComponentTree: { getClosestInstanceFromNode: ReactDOMComponentTree.getClosestInstanceFromNode,getNodeFromInstance: function (inst) { // inst is an internal instance (but could be a composite) if (inst._renderedComponent) { inst = getHostComponentFromComposite(inst); } if (inst) { return ReactDOMComponentTree.getNodeFromInstance(inst); } else { return null; } } },Mount: ReactMount,Reconciler: ReactReconciler }); }
ReactMount.js源码地址
var ReactMount = { //nextElement就是ReactELement,jsx语法将组件或者div,span等转化为一个ReactElement对象 render: function (nextElement,container,callback) { //将ReactElement对象和container元素传递给_renderSubtreeIntoContainer函数; return ReactMount._renderSubtreeIntoContainer(null,nextElement,callback); },_renderSubtreeIntoContainer: function (parentComponent,callback){ .....//具体源码看上面源码地址 var component = ReactMount._renderNewRootComponent(nextWrappedElement,shouldReuseMarkup,nextContext) ._renderedComponent.getPublicInstance(); return component; },//下面这个函数实现将ReactElement元素,转化为DOM元素并且插入到对应的Container元素中去; _renderNewRootComponent: function (nextElement,context) { //Flag1 下面会有源码解释; //instantiateReactComponent(nextElement,false)函数返回一个组件的实例,该函数源码下面会解释; var componentInstance = instantiateReactComponent(nextElement,false); // The initial render is synchronous but any updates that happen during // rendering,in componentWillMount or componentDidMount,will be batched // according to the current batching strategy. //这个函数是真正的将ReactElement元素插入到DOM元素的,会进入到batchedMountComponentIntoNode函数中; ReactUpdates.batchedUpdates(batchedMountComponentIntoNode,componentInstance,context); var wrapperID = componentInstance._instance.rootID; instancesByReactRootID[wrapperID] = componentInstance; return componentInstance; } } //====================会进入到mountComponentIntoNode函数中 function batchedMountComponentIntoNode(componentInstance,context) { var transaction = ReactUpdates.ReactReconcileTransaction.getPooled( /* useCreateElement */ !shouldReuseMarkup && ReactDOMFeatureFlags.useCreateElement); transaction.perform(mountComponentIntoNode,transaction,context); ReactUpdates.ReactReconcileTransaction.release(transaction); } //==================== function mountComponentIntoNode(wrapperInstance,context) { var markerName; if (ReactFeatureFlags.logTopLevelRenders) { var wrappedElement = wrapperInstance._currentElement.props.child; var type = wrappedElement.type; markerName = 'React mount: ' + (typeof type === 'string' ? type : type.displayName || type.name); console.time(markerName); } //Flag2 下面会有源码解释 //markup是经过解析成功的HTML元素,该元素通过_mountImageIntoNode加载到对应的DOM元素上; var markup = ReactReconciler.mountComponent(wrapperInstance,ReactDOMContainerInfo(wrapperInstance,container),context,0 /* parentDebugID */ ); if (markerName) { console.timeEnd(markerName); } wrapperInstance._renderedComponent._topLevelWrapper = wrapperInstance; ReactMount._mountImageIntoNode(markup,wrapperInstance,transaction); } //_mountImageIntoNode _mountImageIntoNode: function (markup,instance,transaction) { !isValidContainer(container) ? process.env.NODE_ENV !== 'production' ? invariant(false,'mountComponentIntoNode(...): Target container is not valid.') : _prodInvariant('41') : void 0; if (shouldReuseMarkup) { var rootElement = getReactRootElementInContainer(container); if (ReactMarkupChecksum.canReuseMarkup(markup,rootElement)) { ReactDOMComponentTree.precacheNode(instance,rootElement); return; } else { var checksum = rootElement.getAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME); rootElement.removeAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME); var rootMarkup = rootElement.outerHTML; rootElement.setAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME,checksum); var normalizedMarkup = markup; var diffIndex = firstDifferenceIndex(normalizedMarkup,rootMarkup); var difference = ' (client) ' + normalizedMarkup.substring(diffIndex - 20,diffIndex + 20) + '\n (server) ' + rootMarkup.substring(diffIndex - 20,diffIndex + 20); if (transaction.useCreateElement) { while (container.lastChild) { container.removeChild(container.lastChild); } DOMLazyTree.insertTreeBefore(container,markup,null); } else { // 利用innerHTML将markup插入到container这个DOM元素上 setInnerHTML(container,markup); // 将instance(Virtual DOM)保存到container这个DOM元素的firstChild这个原生节点上 ReactDOMComponentTree.precacheNode(instance,container.firstChild); } if (process.env.NODE_ENV !== 'production') { var hostNode = ReactDOMComponentTree.getInstanceFromNode(container.firstChild); if (hostNode._debugID !== 0) { ReactInstrumentation.debugTool.onHostOperation({ instanceID: hostNode._debugID,type: 'mount',payload: markup.toString() }); } } }
至此,从创建React组件,到组件加载到DOM 节点上的大致过程已经理顺;
接下来解释下Flag1 和Flag2标记处源码
//Flag1 下面会有源码解释; //instantiateReactComponent(nextElement,false)函数返回一个组件的实例 var componentInstance = instantiateReactComponent(nextElement,false);
instantiateReactComponent.js源码地址
var ReactCompositeComponent = require('./ReactCompositeComponent'); var ReactEmptyComponent = require('./ReactEmptyComponent'); var ReactHostComponent = require('./ReactHostComponent'); // To avoid a cyclic dependency,we create the final class in this module var ReactCompositeComponentWrapper = function (element) { this.construct(element); }; function instantiateReactComponent(node,shouldHaveDebugID) { var instance; if (node === null || node === false) { //situation1:ReactEmptyComponent组件实例 instance = ReactEmptyComponent.create(instantiateReactComponent); } else if (typeof node === 'object') { var element = node; var type = element.type; if (typeof type !== 'function' && typeof type !== 'string') { var info = ''; if (process.env.NODE_ENV !== 'production') { if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) { info += ' You likely forgot to export your component from the file ' + "it's defined in."; } } info += getDeclarationErrorAddendum(element._owner); !false ? process.env.NODE_ENV !== 'production' ? invariant(false,'Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s',type == null ? type : typeof type,info) : _prodInvariant('130',info) : void 0; } // Special case string values if (typeof element.type === 'string') { //situation2:浏览器宿主实例,比如div,span等 instance = ReactHostComponent.createInternalComponent(element); } else if (isInternalComponentType(element.type)) { // This is temporarily available for custom components that are not string // representations. I.e. ART. Once those are updated to use the string // representation,we can drop this code path. //situation3: instance = new element.type(element); // We renamed this. Allow the old name for compat. :( if (!instance.getHostNode) { instance.getHostNode = instance.getNativeNode; } } else { //situation4:React自定义组件,比如通过class等定义的组件; instance = new ReactCompositeComponentWrapper(element); } } else if (typeof node === 'string' || typeof node === 'number') { // situation5:// 元素是一个string时,对应的比如<span>123</span> 中的123,和situation2是一样的; // 本质上它不是一个ReactElement,但为了统一,也按照同样流程处理,称为ReactDOMTextComponent instance = ReactHostComponent.createInstanceForText(node); } else { !false ? process.env.NODE_ENV !== 'production' ? invariant(false,'Encountered invalid React node of type %s',typeof node) : _prodInvariant('131',typeof node) : void 0; } if (process.env.NODE_ENV !== 'production') { process.env.NODE_ENV !== 'production' ? warning(typeof instance.mountComponent === 'function' && typeof instance.receiveComponent === 'function' && typeof instance.getHostNode === 'function' && typeof instance.unmountComponent === 'function','Only React Components can be mounted.') : void 0; } // These two fields are used by the DOM and ART diffing algorithms // respectively. Instead of using expandos on components,we should be // storing the state needed by the diffing algorithms elsewhere. instance._mountIndex = 0; instance._mountImage = null; if (process.env.NODE_ENV !== 'production') { instance._debugID = shouldHaveDebugID ? getNextDebugID() : 0; } // Internal instances should fully constructed at this point,so they should // not get any new fields added to them at this point. if (process.env.NODE_ENV !== 'production') { if (Object.preventExtensions) { Object.preventExtensions(instance); } } return instance; }
接下来看下这几种实例的创建源码
situation1:instance = ReactEmptyComponent.create(instantiateReactComponent);
var emptyComponentFactory; var ReactEmptyComponentInjection = { injectEmptyComponentFactory: function (factory) { emptyComponentFactory = factory; } }; var ReactEmptyComponent = { create: function (instantiate) { return emptyComponentFactory(instantiate); } }; ReactEmptyComponent.injection = ReactEmptyComponentInjection; ReactInjection.EmptyComponent.injectEmptyComponentFactory(function (instantiate) { // 前面比较绕,关键就是这句话,创建ReactDOMEmptyComponent对象 return new ReactDOMEmptyComponent(instantiate); }); // 各种null,就不分析了 var ReactDOMEmptyComponent = function (instantiate) { this._currentElement = null; this._nativeNode = null; this._nativeParent = null; this._nativeContainerInfo = null; this._domID = null; }; //这里的_assign就是Object.assign函数 _assign(ReactCompositeComponentWrapper.prototype,ReactCompositeComponent,{ _instantiateReactComponent: instantiateReactComponent });
situation2:instance = ReactHostComponent.createInternalComponent(element);这个其实就是创建宿主元素实例
situation5:instance = ReactHostComponent.createInstanceForText(node);
在宿主元素实例上也有mountComponent方法;在生成markup的时候,对于函数,class组件实例,会递归生成新的实例,直到宿主DOM元素;
ReactDOMComponent.js源码地址
ReactDOMTextComponent.js源码地址
从源码可以看到,instance上都有mountComponent函数,和ReactCompositeComponent.js中的mountComponent函数一样,对于不同的ReactElement对象执行不同的mountComponent函数;
区别在于ReactCompositeComponent.js中的mountComponent会递归的生成instance直到ReactElement的type类型为string,然后执行ReactDOMComponent.js或者ReactDOMTextComponent.js的mountComponent函数,生成最终的DOM元素,挂载到节点上;
重点来看下
situation4:React自定义组件。
instance = new ReactCompositeComponentWrapper(element); //组件实例上有了constructor函数执行之后的所有属性以及ReactCompositeComponent对象上的所有方法,其中包括mountComponent方法,注意上文Flag2处的 var markup = ReactReconciler.mountComponent(wrapperInstance,0 );
在instantiateReactComponent.js的源码中,如下是ReactCompositeComponentWrapper函数的定义,该函数接受ReactElement对象作为参数
var ReactCompositeComponentWrapper = function (element) { this.construct(element); };
然后执行 new ReactCompositeComponentWrapper(element)的时候,会执行this.constructor(element);那么constructor是哪里来的呢?
//Object.assign _assign(ReactCompositeComponentWrapper.prototype,{ _instantiateReactComponent: instantiateReactComponent }); //这就使得instance = new ReactCompositeComponentWrapper(element);会执行下面的constructor方法;instance实例上有ReactCompositeComponent这个对象上的所有属性和方法,其中React组件实例上会有constructor和mountComponent函数 //注意这里并没有实例化class组件(函数),真正new class组件(函数)是在mountComponent中进行的;这里只是让instance上可以访问到ReactElement对象(type,props.....):this._currentElement = element;
ReactCompositeComponent.js源码地址
这里暂时只分析class类创建的组件渲染底层实现的代码,其余代码不贴;
var ReactCompositeComponent = { /** * Base constructor for all composite component. * * @param {ReactElement} element * @final * @internal */ construct: function (element) { this._currentElement = element; this._rootNodeID = 0; this._compositeType = null; this._instance = null; this._hostParent = null; this._hostContainerInfo = null; // See ReactUpdateQueue this._updateBatchNumber = null; this._pendingElement = null; this._pendingStateQueue = null; this._pendingReplaceState = false; this._pendingForceUpdate = false; this._renderedNodeType = null; this._renderedComponent = null; this._context = null; this._mountOrder = 0; this._topLevelWrapper = null; // See ReactUpdates and ReactUpdateQueue. this._pendingCallbacks = null; // ComponentWillUnmount shall only be called once this._calledComponentWillUnmount = false; if (process.env.NODE_ENV !== 'production') { this._warnedAboutRefsInRender = false; } },/** * Initializes the component,renders markup,and registers event listeners. * * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction * @param {?object} hostParent * @param {?object} hostContainerInfo * @param {?object} context * @return {?string} Rendered markup to be inserted into the DOM. * @final * @internal */ mountComponent: function (transaction,hostParent,hostContainerInfo,context) { var _this = this; this._context = context; this._mountOrder = nextMountID++; this._hostParent = hostParent; this._hostContainerInfo = hostContainerInfo; //ReactElement对象中的props,type等的声明; var publicProps = this._currentElement.props; var publicContext = this._processContext(context); var Component = this._currentElement.type;//class声明的React组件(函数)_constructComponentWithoutOwner函数中初始化为实例对象; var updateQueue = transaction.getUpdateQueue(); // Initialize the public class var doConstruct = shouldConstruct(Component); //这里的inst就是new class组件生成的实力对象;_constructComponent下面有贴上源码; var inst = this._constructComponent(doConstruct,publicProps,publicContext,updateQueue); var renderedElement; // These should be set up in the constructor,but as a convenience for // simpler class abstractions,we set them up after the fact. //将ReactElement对象上的props,refs给到React组件的实例对象; //这就是为什么在组件中通过this.props可以访问到对应的属性值的原因; /** class Welcome extends React.Component { render(){ return <h1>hello {this.props.name}</h1> } } const element = <Welcome name = 'JiM'/> 通过JSX生成ReactElement对象,生成这个对象,会成为instance = new ReactCompositeComponentWrapper(element);对象的一个属性,_currentElement;同时instance上有mountComponent方法;当Flag2处生成markup的时候,会调用这个方法,在这个方法中会new class组件,生成实例对象; */ inst.props = publicProps; inst.context = publicContext; inst.refs = emptyObject; inst.updater = updateQueue; this._instance = inst; // Store a reference from the instance back to the internal representation ReactInstanceMap.set(inst,this); var initialState = inst.state; if (initialState === undefined) { inst.state = initialState = null; } !(typeof initialState === 'object' && !Array.isArray(initialState)) ? process.env.NODE_ENV !== 'production' ? invariant(false,'%s.state: must be set to an object or null',this.getName() || 'ReactCompositeComponent') : _prodInvariant('106',this.getName() || 'ReactCompositeComponent') : void 0; this._pendingStateQueue = null; this._pendingReplaceState = false; this._pendingForceUpdate = false; var markup; //对于class创建的React组件来说,renderedElement = inst.render();下面的函数内部会调用组件实例的render方法;这里不在深入研究; if (inst.unstable_handleError) { markup = this.performInitialMountWithErrorHandling(renderedElement,context); } else { //这里进行递归的生成组件实例,直到renderElement是宿主DOM元素的时候;下面有源码; markup = this.performInitialMount(renderedElement,context); } if (inst.componentDidMount) { if (process.env.NODE_ENV !== 'production') { transaction.getReactMountReady().enqueue(function () { measureLifeCyclePerf(function () { return inst.componentDidMount(); },_this._debugID,'componentDidMount'); }); } else { transaction.getReactMountReady().enqueue(inst.componentDidMount,inst); } } return markup; },performInitialMount: function (renderedElement,context) { var inst = this._instance; var debugID = 0; if (process.env.NODE_ENV !== 'production') { debugID = this._debugID; } if (inst.componentWillMount) { if (process.env.NODE_ENV !== 'production') { measureLifeCyclePerf(function () { return inst.componentWillMount(); },debugID,'componentWillMount'); } else { inst.componentWillMount(); } // When mounting,calls to `setState` by `componentWillMount` will set // `this._pendingStateQueue` without triggering a re-render. if (this._pendingStateQueue) { inst.state = this._processPendingState(inst.props,inst.context); } } // If not a stateless component,we now render if (renderedElement === undefined) { renderedElement = this._renderValidatedComponent(); } var nodeType = ReactNodeTypes.getType(renderedElement); this._renderedNodeType = nodeType; //如果是child是class生成的ReactElement对象,即type类型为函数,此时child上的mountComponent引用的是而ReactCompositeComponent.js中的mountComponent,则继续递归生成markup,直到child是宿主ReactElement对象,即type类型为字符串,此时child上mountComponent引用的是,ReactDOMComponent.js中的mountComponent,则最终生成DOM元素,插入到节点中; var child = this._instantiateReactComponent(renderedElement,nodeType !== ReactNodeTypes.EMPTY /* shouldHaveDebugID */ ); this._renderedComponent = child; //ReactReconciler.mountComponent会调用组件实例的mountComponent函数,这里对于函数组件;会调用ReactCompositeComponent.js中的mountComponent //这里进行递归调用ReactCompositeComponent.js中的mountComponent函数,而ReactCompositeComponent.js中的mountComponent中又调用performInitialMount形成递归; //直到组件是宿主DOM对象的时候,生成markup的时候,会调用 var markup = ReactReconciler.mountComponent(child,this._processChildContext(context),debugID); if (process.env.NODE_ENV !== 'production') { if (debugID !== 0) { var childDebugIDs = child._debugID !== 0 ? [child._debugID] : []; ReactInstrumentation.debugTool.onSetChildren(debugID,childDebugIDs); } } return markup; },_constructComponent: function (doConstruct,updateQueue) { if (process.env.NODE_ENV !== 'production' && !doConstruct) { ReactCurrentOwner.current = this; try { return this._constructComponentWithoutOwner(doConstruct,updateQueue); } finally { ReactCurrentOwner.current = null; } } else { return this._constructComponentWithoutOwner(doConstruct,updateQueue); } },_constructComponentWithoutOwner: function (doConstruct,updateQueue) { var Component = this._currentElement.type; if (doConstruct) { if (process.env.NODE_ENV !== 'production') { return measureLifeCyclePerf(function () { //这里的Component就是ReactElement中的type,new该type的时候,如果是class声明的,会直接执行class类中的constructor函数;返回一个组件实例对象; return new Component(publicProps,updateQueue); },this._debugID,'ctor'); } else { return new Component(publicProps,updateQueue); } } // This can still be an instance in case of factory components // but we'll count this as time spent rendering as the more common case. if (process.env.NODE_ENV !== 'production') { return measureLifeCyclePerf(function () { return Component(publicProps,updateQueue); },'render'); } else { return Component(publicProps,}
接下来看下Flag2的解释
var markup = ReactReconciler.mountComponent(wrapperInstance,0 )
ReactReconciler.js源码地址
var ReactReconciler = { /** * Initializes the component,and registers event listeners. * * @param {ReactComponent} internalInstance * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction * @param {?object} the containing host component instance * @param {?object} info about the host container * @return {?string} Rendered markup to be inserted into the DOM. * @final * @internal */ mountComponent: function (internalInstance,parentDebugID) // 0 in production and for roots { if (process.env.NODE_ENV !== 'production') { if (internalInstance._debugID !== 0) { ReactInstrumentation.debugTool.onBeforeMountComponent(internalInstance._debugID,internalInstance._currentElement,parentDebugID); } } //注意这里internalInstance.mountComponent其实就是ReactCompositeComponent.js中的mountComponent方法; var markup = internalInstance.mountComponent(transaction,parentDebugID); if (internalInstance._currentElement && internalInstance._currentElement.ref != null) { transaction.getReactMountReady().enqueue(attachRefs,internalInstance); } if (process.env.NODE_ENV !== 'production') { if (internalInstance._debugID !== 0) { ReactInstrumentation.debugTool.onMountComponent(internalInstance._debugID); } } return markup; },........ //其他方法....... }
6 总结
- React.js负责创建一个虚拟DOM对象,这个对象以一个大的ReactElement对象的形式存在;
-
ReactDOM.js负责将虚拟DOM对象挂在到真正的DOM 根节点上,
react如何将ReactElement加载到DOM
ReactCreateClass源码解析
ReactDOM.render源码解析
ReactCompositeComponent的源码实现
babel转译网站