日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

react源码解读 {createClass}

發(fā)布時間:2023/12/10 编程问答 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 react源码解读 {createClass} 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
對一個框架源碼的解讀,既有利于更深入地了解框架,使用上更得心應手,又可以學習到其中代碼組織的思路,吸收其精華簡潔的寫法以便于日常工作上使用。下面我就挑選近年大熱門react(15.3.1),從中剖析框架的設計思路,由淺入深地學習。

我們從這個文件開始看起,這是react的主入口(./lib/react.js)。

/*** Copyright 2013-present, Facebook, Inc.* All rights reserved.** This source code is licensed under the BSD-style license found in the* LICENSE file in the root directory of this source tree. An additional grant* of patent rights can be found in the PATENTS file in the same directory.** @providesModule React*/'use strict';var _assign = require('object-assign');var ReactChildren = require('./ReactChildren'); var ReactComponent = require('./ReactComponent'); var ReactPureComponent = require('./ReactPureComponent'); var ReactClass = require('./ReactClass'); var ReactDOMFactories = require('./ReactDOMFactories'); var ReactElement = require('./ReactElement'); var ReactPropTypes = require('./ReactPropTypes'); var ReactVersion = require('./ReactVersion');var onlyChild = require('./onlyChild'); var warning = require('fbjs/lib/warning');var createElement = ReactElement.createElement; var createFactory = ReactElement.createFactory; var cloneElement = ReactElement.cloneElement;if (process.env.NODE_ENV !== 'production') {var ReactElementValidator = require('./ReactElementValidator');createElement = ReactElementValidator.createElement;createFactory = ReactElementValidator.createFactory;cloneElement = ReactElementValidator.cloneElement; }var __spread = _assign;if (process.env.NODE_ENV !== 'production') {var warned = false;__spread = function () {process.env.NODE_ENV !== 'production' ? warning(warned, 'React.__spread is deprecated and should not be used. Use ' + 'Object.assign directly or another helper function with similar ' + 'semantics. You may be seeing this warning due to your compiler. ' + 'See https://fb.me/react-spread-deprecation for more details.') : void 0;warned = true;return _assign.apply(null, arguments);}; }var React = {// ModernChildren: {map: ReactChildren.map,forEach: ReactChildren.forEach,count: ReactChildren.count,toArray: ReactChildren.toArray,only: onlyChild},Component: ReactComponent,PureComponent: ReactPureComponent,createElement: createElement,cloneElement: cloneElement,isValidElement: ReactElement.isValidElement,// ClassicPropTypes: ReactPropTypes,createClass: ReactClass.createClass,createFactory: createFactory,createMixin: function (mixin) {// Currently a noop. Will be used to validate and trace mixins.return mixin;},// 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 };module.exports = React;

我們直接跳過前面的環(huán)境判斷以及模塊引入,可以看到從50行起就是React的關鍵代碼。并且我們可以清晰的從上面看到React所提供的方法。這是離我們使用者最近的一層,看到信息量不多。我們就按照開發(fā)的思路,一步一步地深入源碼。
編寫一個組件,當然是從創(chuàng)建開始,我們使用的是 React.createClass,不難發(fā)現,React.createClass實際上引用的是ReactClass.createClass。當然我們也可以用ES6的寫法直接繼承至React.Component.這兩種寫法有什么差異存在,我們先把懸念放在后面。
先從createClass的源碼看起(./lib/ReactClass)。

var ReactClass = {/*** Creates a composite component class given a class specification.* See https://facebook.github.io/react/docs/top-level-api.html#react.createclass** @param {object} spec Class specification (which must define `render`).* @return {function} Component constructor function.* @public*/createClass: function (spec) {var Constructor = function (props, context, updater) {// This constructor gets overridden by mocks. The argument is used// by mocks to assert on what gets mounted.if (process.env.NODE_ENV !== 'production') {process.env.NODE_ENV !== 'production' ? warning(this instanceof Constructor, 'Something is calling a React component directly. Use a factory or ' + 'JSX instead. See: https://fb.me/react-legacyfactory') : void 0;}// Wire up auto-bindingif (this.__reactAutoBindPairs.length) {bindAutoBindMethods(this);}this.props = props;this.context = context;this.refs = emptyObject;this.updater = updater || ReactNoopUpdateQueue;this.state = null;// ReactClasses doesn't have constructors. Instead, they use the// getInitialState and componentWillMount methods for initialization.var initialState = this.getInitialState ? this.getInitialState() : null;if (process.env.NODE_ENV !== 'production') {// We allow auto-mocks to proceed as if they're returning null.if (initialState === undefined && this.getInitialState._isMockFunction) {// This is probably bad practice. Consider warning here and// deprecating this convenience.initialState = null;}}!(typeof initialState === 'object' && !Array.isArray(initialState)) ? process.env.NODE_ENV !== 'production' ? invariant(false, '%s.getInitialState(): must return an object or null', Constructor.displayName || 'ReactCompositeComponent') : _prodInvariant('82', Constructor.displayName || 'ReactCompositeComponent') : void 0;this.state = initialState;};Constructor.prototype = new ReactClassComponent();Constructor.prototype.constructor = Constructor;Constructor.prototype.__reactAutoBindPairs = [];injectedMixins.forEach(mixSpecIntoComponent.bind(null, Constructor));mixSpecIntoComponent(Constructor, spec);// Initialize the defaultProps property after all mixins have been merged.if (Constructor.getDefaultProps) {Constructor.defaultProps = Constructor.getDefaultProps();}if (process.env.NODE_ENV !== 'production') {// This is a tag to indicate that the use of these method names is ok,// since it's used with createClass. If it's not, then it's likely a// mistake so we'll warn you to use the static property, property// initializer or constructor respectively.if (Constructor.getDefaultProps) {Constructor.getDefaultProps.isReactClassApproved = {};}if (Constructor.prototype.getInitialState) {Constructor.prototype.getInitialState.isReactClassApproved = {};}}!Constructor.prototype.render ? process.env.NODE_ENV !== 'production' ? invariant(false, 'createClass(...): Class specification must implement a `render` method.') : _prodInvariant('83') : void 0;if (process.env.NODE_ENV !== 'production') {process.env.NODE_ENV !== 'production' ? warning(!Constructor.prototype.componentShouldUpdate, '%s has a method called ' + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + 'The name is phrased as a question because the function is ' + 'expected to return a value.', spec.displayName || 'A component') : void 0;process.env.NODE_ENV !== 'production' ? warning(!Constructor.prototype.componentWillRecieveProps, '%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', spec.displayName || 'A component') : void 0;}// Reduce time spent doing lookups by setting these on the prototype.for (var methodName in ReactClassInterface) {if (!Constructor.prototype[methodName]) {Constructor.prototype[methodName] = null;}}return Constructor;},injection: {injectMixin: function (mixin) {injectedMixins.push(mixin);}}};

644行起,createClass方法首先定義了一個Constructor構造函數,折疊內部,我們看看這個方法在返回一個構造函數前做了什么,
直接跳到681行,構造函數的prototype指向一個ReactClassComponent的實例。

Constructor.prototype = new ReactClassComponent();

往上翻我們可以發(fā)現,ReactClassComponent的prototype屬性,拷貝了ReactComponent.prototype 和 ReactClassMixin,因此我們的組件可以使用ReactComponent原型上的方法。

var ReactClassComponent = function () {}; _assign(ReactClassComponent.prototype, ReactComponent.prototype, ReactClassMixin);

683行到687行。
定義了 __reactAutoBindPairs 為一個空數組。
先將mixin里面的方法按照key,function內容的順序成對存入 __reactAutoBindPairs ,
接著就是spec對象里的方法用同樣的方式存入。

Constructor.prototype.__reactAutoBindPairs = [];injectedMixins.forEach(mixSpecIntoComponent.bind(null, Constructor));mixSpecIntoComponent(Constructor, spec);

690行我們可以看到Constructor.defaultProps 就是我們開發(fā)中 getDefaultProps()所返回的對象。

if (Constructor.getDefaultProps) {Constructor.defaultProps = Constructor.getDefaultProps();}

694行 -- 712行 是在開發(fā)環(huán)境中對開發(fā)者的建議,以及規(guī)范使用的警示。
715行 -- 719行 可以知道我們創(chuàng)建一個組件需要定義的方法都在ReactClassInterface上有,當前未定義的方法設置為空,我們就可以通過打印組件的prototype屬性清楚地在日志上知道我們有哪些api是未定義的。通過設置未定義的屬性為空,可以減少程序查找的時間。
721行 最終返回了這個封裝好的構造函數。

for (var methodName in ReactClassInterface) {if (!Constructor.prototype[methodName]) {Constructor.prototype[methodName] = null;}}return Constructor;

看到這里我們可以明白一點,組件實質上是一個構造函數,而我們自定義的方法,既存在了prototype里,也按照[key,content,key,content...]的方式歸納到了Constructor.prototype.__reactAutoBindPairs 里。這是為了組件實例化時可以將這些方法直接遍歷綁定在實例上,并且避免了React官方指定的方法也被綁定在實例上。

接下來我們展開645行的Constructor,可以看到實例化的時候主要做了兩件事。
654行
第一件事就是將上文提到的存在Constructor.prototype.__reactAutoBindPairs 的內容成對取出,綁定在實例上。

if (this.__reactAutoBindPairs.length) {bindAutoBindMethods(this);}

668行 ——679行
第二件事就是判斷組件是否有定義getInitialState,如果有,則將state設置為該方法返回的值,如果沒有設置state為null。

var initialState = this.getInitialState ? this.getInitialState() : null;if (process.env.NODE_ENV !== 'production') {// We allow auto-mocks to proceed as if they're returning null.if (initialState === undefined && this.getInitialState._isMockFunction) {// This is probably bad practice. Consider warning here and// deprecating this convenience.initialState = null;}}!(typeof initialState === 'object' && !Array.isArray(initialState)) ? process.env.NODE_ENV !== 'production' ? invariant(false, '%s.getInitialState(): must return an object or null', Constructor.displayName || 'ReactCompositeComponent') : _prodInvariant('82', Constructor.displayName || 'ReactCompositeComponent') : void 0;this.state = initialState;

到這里我們大概地知道了一個組件從創(chuàng)建構造函數到實例化的時候做了什么事情了。后續(xù)我們繼續(xù)解讀更底層的ReactComponent。

希望能對大家有幫助。
如果有錯誤的地方,懇請各位大神指正。

總結

以上是生活随笔為你收集整理的react源码解读 {createClass}的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。