摘要:的創建組件,其實根源還是調用了編譯之后一般寫法建議用來進行源碼的跟蹤鏈接從源碼角度來看創建一個組件的過程中發生了什么。
https://github.com/jimwmg/Rea...
1 React.createClass( )
2 React.Component
ES6的創建組件,其實根源還是調用了createClass
編譯之后
"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 = ()=>(this is Repo) const Category = (props)=>{ console.log(props); return (this is category) } const MyTest =()=>() export default MyTest
- About
- Repo
- Category
{console.log(props);return ( this is aabout) }}>{console.log(props);return ( this is a component build througth children) }}>
ES6一般寫法
const BasicExample = () => ()
- Home
- About
- Topics
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, 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) + " (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時,對應的比如123 中的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(){ returnhello {this.props.name}
} } const element =通過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 總結
React.js負責創建一個虛擬DOM對象,這個對象以一個大的ReactElement對象的形式存在;
ReactDOM.js負責將虛擬DOM對象掛在到真正的DOM 根節點上,
對于class組件,會調用其render函數的返回值作為renderedElement的值,進行遞歸掛載
對于宿主DOM對象,則直接將其掛載
react如何將ReactElement加載到DOM
ReactCreateClass源碼解析
ReactDOM.render源碼解析
ReactCompositeComponent的源碼實現
babel轉譯網站
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/89089.html
摘要:查看創建核心函數源碼行調用函數創建是相關,不用管源碼行這個指的是調用創建,下面我們將會說到對象源碼行源碼行函數中,首先創建了一個,然后又創建了一個,它們兩者還是相互引用。 感謝 yck: 剖析 React 源碼解析,本篇文章是在讀完他的文章的基礎上,將他的文章進行拆解和加工,加入我自己的一下理解和例子,便于大家理解。覺得yck寫的真的很棒 。React 版本為 16.8.6,關于源碼的...
摘要:本文將對源碼做一個初步解析。首先在方法中校驗參數是否合法,然后調用在中,調用拿到了的一個實例,調用拿到了,用于注入到,和作為返回值,調用開始調度過程在中,首先清理了中的所有子節點,然后了一個并返回是如何調度的是一個什么樣的類的操作是在哪里 初步看了react-dom這個包的一些源碼,發現其比react包要復雜得多,react包中基本不存在跨包調用的情況,他所做的也僅僅是定義了React...
摘要:一更新的方式有三種渲染接下來,我們就來看下源碼二作用在提供的里渲染一個元素,并返回對該組件的引用常見的用法是這個官網網址源碼服務端使用方法渲染節點是讓服務端盡可能復用節點,提高性能元素容器應用渲染結束后,調用的函數錯誤抓取方法本質是返回 showImg(https://segmentfault.com/img/remote/1460000020064414?w=1240&h=641);...
摘要:就是,如果你不了解這個的話可以閱讀下相關文檔,是應用初始化時就會生成的一個變量,值也是,并且這個值不會在后期再被改變。這是我的剖析 React 源碼的第三篇文章,如果你沒有閱讀過之前的文章,請務必先閱讀一下 第一篇文章 中提到的一些注意事項,能幫助你更好地閱讀源碼。 文章相關資料 React 16.8.6 源碼中文注釋,這個鏈接是文章的核心,文中的具體代碼及代碼行數都是依托于這個倉庫 熱身...
摘要:調用棧是這樣的這里生成的我們將其命名為,它將作為參數傳入到。整個的調用棧是這樣的組件間的層級結構是這樣的到此為止,頂層對象已經構造完畢,下一步就是調用來自的方法,進行頁面的渲染了。通過表達的結構最終會轉化為一個純對象,用于下一步的渲染。 歡迎關注我的公眾號睿Talk,獲取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、前言...
閱讀 3708·2023-04-26 00:56
閱讀 2686·2021-09-30 10:01
閱讀 961·2021-09-22 15:30
閱讀 3915·2021-09-07 10:21
閱讀 1507·2021-09-02 15:40
閱讀 2750·2021-08-30 09:47
閱讀 1234·2021-08-16 10:57
閱讀 1862·2019-08-30 14:01