https://github.com/jimwmg/Rea...node
1 React.createClass( )react
<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.Componentgit
ES6的建立組件,其實根源仍是調用了createClassgithub
<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>
編譯以後web
"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 functionexpress
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.jsbabel
從源碼角度來看建立一個React組件的過程當中發生了什麼。react-router
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, version: ReactVersion, /* 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, container, callback); }, _renderSubtreeIntoContainer: function (parentComponent, nextElement, container, callback){ .....//具體源碼看上面源碼地址 var component = ReactMount._renderNewRootComponent(nextWrappedElement, container, shouldReuseMarkup, nextContext) ._renderedComponent.getPublicInstance(); return component; }, //下面這個函數實現將ReactElement元素,轉化爲DOM元素而且插入到對應的Container元素中去; _renderNewRootComponent: function (nextElement, container, shouldReuseMarkup, 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, container, shouldReuseMarkup, context); var wrapperID = componentInstance._instance.rootID; instancesByReactRootID[wrapperID] = componentInstance; return componentInstance; } } //====================會進入到mountComponentIntoNode函數中 function batchedMountComponentIntoNode(componentInstance, container, shouldReuseMarkup, context) { var transaction = ReactUpdates.ReactReconcileTransaction.getPooled( /* useCreateElement */ !shouldReuseMarkup && ReactDOMFeatureFlags.useCreateElement); transaction.perform(mountComponentIntoNode, null, componentInstance, container, transaction, shouldReuseMarkup, context); ReactUpdates.ReactReconcileTransaction.release(transaction); } //==================== function mountComponentIntoNode(wrapperInstance, container, transaction, shouldReuseMarkup, 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, transaction, null, ReactDOMContainerInfo(wrapperInstance, container), context, 0 /* parentDebugID */ ); if (markerName) { console.timeEnd(markerName); } wrapperInstance._renderedComponent._topLevelWrapper = wrapperInstance; ReactMount._mountImageIntoNode(markup, container, wrapperInstance, shouldReuseMarkup, transaction); } //_mountImageIntoNode _mountImageIntoNode: function (markup, container, instance, shouldReuseMarkup, 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', type == null ? type : typeof type, 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, transaction, null, ReactDOMContainerInfo(wrapperInstance, container), context, 0 );
在instantiateReactComponent.js的源碼中,以下是ReactCompositeComponentWrapper函數的定義,該函數接受ReactElement對象做爲參數
var ReactCompositeComponentWrapper = function (element) { this.construct(element); };
而後執行 new ReactCompositeComponentWrapper(element)的時候,會執行this.constructor(element);那麼constructor是哪裏來的呢?
//Object.assign _assign(ReactCompositeComponentWrapper.prototype, ReactCompositeComponent, { _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,context,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,context,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, hostParent, hostContainerInfo, transaction, context); } else { //這裏進行遞歸的生成組件實例,直到renderElement是宿主DOM元素的時候;下面有源碼; markup = this.performInitialMount(renderedElement, hostParent, hostContainerInfo, transaction, 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, hostParent, hostContainerInfo, transaction, 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, transaction, hostParent, hostContainerInfo, 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, publicProps, publicContext, updateQueue) { if (process.env.NODE_ENV !== 'production' && !doConstruct) { ReactCurrentOwner.current = this; try { return this._constructComponentWithoutOwner(doConstruct, publicProps, publicContext, updateQueue); } finally { ReactCurrentOwner.current = null; } } else { return this._constructComponentWithoutOwner(doConstruct, publicProps, publicContext, updateQueue); } }, _constructComponentWithoutOwner: function (doConstruct, publicProps, publicContext, 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, publicContext, updateQueue); }, this._debugID, 'ctor'); } else { return new Component(publicProps, publicContext, 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, publicContext, updateQueue); }, this._debugID, 'render'); } else { return Component(publicProps, publicContext, updateQueue); } }, }
接下來看下Flag2的解釋
var markup = ReactReconciler.mountComponent(wrapperInstance, transaction, null, ReactDOMContainerInfo(wrapperInstance, container), context, 0 )
ReactReconciler.js源碼地址
var ReactReconciler = { /** * Initializes the component, renders markup, 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, transaction, hostParent, hostContainerInfo, context, 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, hostParent, hostContainerInfo, context, 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 總結
ReactDOM.js負責將虛擬DOM對象掛在到真正的DOM 根節點上,
react如何將ReactElement加載到DOM
ReactCreateClass源碼解析
ReactDOM.render源碼解析
ReactCompositeComponent的源碼實現
babel轉譯網站