React 源碼閱讀-10
ReactBaseClasses
這個文件是export
出了Component
, PureComponent
export {Component, PureComponent};
源碼+註釋
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
//生產環境使用,爲了拋出錯誤信息
import invariant from 'shared/invariant';
//只在開發環境有效,使用 console.warn(message);
import lowPriorityWarning from 'shared/lowPriorityWarning';
//沒有傳入參數updater參數時,this.updater的值就是ReactNoopUpdateQueue
//用於報警告的 可以忽略
import ReactNoopUpdateQueue from './ReactNoopUpdateQueue';
const emptyObject = {};
if (__DEV__) {
Object.freeze(emptyObject);
// Object.freeze() 方法可以凍結一個對象。一個被凍結的對象再也不能被修改;凍結了一個對象則不能向這個對象添加新的屬性,不能刪除已有屬性,不能修改該對象已有屬性的可枚舉性、可配置性、可寫性,以及不能修改已有屬性的值。此外,凍結一個對象後該對象的原型也不能被修改。freeze() 返回和傳入的參數相同的對象
}
/**
* Base class helpers for the updating state of a component.
*/
// Base class用於更新組件的state。\
// Component()本質是一個類:
function Component(props, context, updater) {
this.props = props;
this.context = context;
// If a component has string refs, we will assign a different object later.
// 如果組件ref具有字符串引用,稍後將分配一個不同的對象
this.refs = emptyObject;
// We initialize the default updater but the real one gets injected by the
// renderer.
// 我們初始化默認的更新程序,但是真正的更新程序會被渲染
this.updater = updater || ReactNoopUpdateQueue;
}
Component.prototype.isReactComponent = {};
/**
*不能保證`this.state`會立即更新,因此
*調用此方法後訪問`this.state`可能會返回舊值。
*
*不能保證對setState的調用將同步運行,
*因爲它們最終可能會一起批處理。您可以提供可選
*實際調用setState時將執行的回調
*完成。
*
*將函數提供給setState時,它將在以下時間點被調用
*未來(不同步)。它將被稱爲最新
*組件參數(狀態,道具,上下文)。這些值可以不同
*from this。*因爲您的函數可能在receiveProps之後但之前被調用
*shouldComponentUpdate,這個新的狀態,道具和上下文還沒有
*分配給這個
*
* @param {object|function} partialState Next partial state or function to
* produce next partial state to be merged with current state.
* @param {?function} callback Called after state is updated.
* @final
* @protected
*/
Component.prototype.setState = function(partialState, callback) {
invariant(
typeof partialState === 'object' ||
typeof partialState === 'function' ||
partialState == null,
'setState(...): takes an object of state variables to update or a ' +
'function which returns an object of state variables.',
);
this.updater.enqueueSetState(this, partialState, callback, 'setState');
};
/**
強制更新。僅當已知時才應調用此方法
*確定我們不是DOM事務中的**。
*
*如果您知道
*組件的狀態已更改,但未調用`setState`。
*
*這不會調用`shouldComponentUpdate`,但是會調用
*componentWillUpdate和componentDidUpdate。
*
* @param {?function} callback Called after update is complete.
* @final
* @protected
*/
Component.prototype.forceUpdate = function(callback) {
this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};
/**
不推薦使用的API。這些API曾經存在於經典的React類上,但是由於
*我們要棄用它們,我們不會將它們移至此
*現代基層。取而代之的是,我們定義了一個getter,如果它被訪問,它會發出警告
已經廢棄
*/
if (__DEV__) {
const deprecatedAPIs = {
isMounted: [
'isMounted',
'Instead, make sure to clean up subscriptions and pending requests in ' +
'componentWillUnmount to prevent memory leaks.',
],
replaceState: [
'replaceState',
'Refactor your code to use setState instead (see ' +
'https://github.com/facebook/react/issues/3236).',
],
};
const defineDeprecationWarning = function(methodName, info) {
Object.defineProperty(Component.prototype, methodName, {
get: function() {
lowPriorityWarning(
false,
'%s(...) is deprecated in plain JavaScript React classes. %s',
info[0],
info[1],
);
return undefined;
},
});
};
for (const fnName in deprecatedAPIs) {
if (deprecatedAPIs.hasOwnProperty(fnName)) {
defineDeprecationWarning(fnName, deprecatedAPIs[fnName]);
}
}
}
//虛擬組件
function ComponentDummy() {}
ComponentDummy.prototype = Component.prototype;
// 帶有默認淺層相等性檢查的便利組件。
/**
* Convenience component with default shallow equality check for sCU.
*/
// PureComponent最佳情況是展示組件
function PureComponent(props, context, updater) {
this.props = props;
this.context = context;
// If a component has string refs, we will assign a different object later.
this.refs = emptyObject;
this.updater = updater || ReactNoopUpdateQueue;
}
const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
// PureComponent.prototype等於ComponentDummy的實例 只繼承Component的原型,不包括constructor,以此來節省內存。
pureComponentPrototype.constructor = PureComponent;
// 原型的constructor等於自身,覆蓋掉Component.prototype的constructor(Component)
// Avoid an extra prototype jump for these methods.
// 對於這些方法,請避免額外的原型跳轉 爲了減少一次原型鏈查找
Object.assign(pureComponentPrototype, Component.prototype);
pureComponentPrototype.isPureReactComponent = true;
// PureComponent是自帶了一個簡單的shouldComponentUpdate來優化更新機制的
export {Component, PureComponent};
https://juejin.im/post/5b614d...