談react優化其中最重要的一個組件就是PureComponent,主要的特點就是當數據即使發生深層次的變化,PureComponent也不會更新而且影響到子組件。
那PureComponent和Component的之間的聯繫在哪裏,以下是對react框架代碼的一些理解。
一、都是從React.js中暴露出來, 刪除多此次不相關代碼
import {Component, PureComponent} from './ReactBaseClasses';
const React = {
Children: {
map,
forEach,
count,
toArray,
only,
},
createRef,
Component,
PureComponent,
};
export default React;
此處可以看到Component都是來自於ReactBaseClasses.js,這樣就很有意思了。PureComponent其實就是繼承自Component, 注意ComponentDummy個人理解爲Component複製品
function Component(props, context, updater) {
this.props = props;
this.context = context;
this.refs = emptyObject;
this.updater = updater || ReactNoopUpdateQueue;
}
Component.prototype.isReactComponent = {};
// 這裏就是很熟悉的setSate
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.',
);
// 爲什麼說 setState異步的,updater更新的是一個隊列
this.updater.enqueueSetState(this, partialState, callback, 'setState');
};
// 強制更新
Component.prototype.forceUpdate = function(callback) {
this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};
// 聲明一個複製品Component,利用其原型繼承Component的原型
function ComponentDummy() {}
ComponentDummy.prototype = Component.prototype;
// 申明PureComponent
function PureComponent(props, context, updater) {
this.props = props;
this.context = context;
this.refs = emptyObject;
this.updater = updater || ReactNoopUpdateQueue;
}
// PureComponent原型再繼承,複製品Component
const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
pureComponentPrototype.constructor = PureComponent;
// assign 淺複製 Component的原型到 PureComponent
Object.assign(pureComponentPrototype, Component.prototype);
// 這裏就是 PureComponent 和 Component 的區別加入了一個 isPureReactComponent = true
pureComponentPrototype.isPureReactComponent = true;
export {Component, PureComponent};
二、淺比較是怎麼發生的
1、我們還是回到React.js 文件中React 包含方法
import {
createElement,
createFactory,
cloneElement,
isValidElement,
} from './ReactElement';
const React = {
createElement: __DEV__ ? createElementWithValidation : createElement,
cloneElement: __DEV__ ? cloneElementWithValidation : cloneElement,
createFactory: __DEV__ ? createFactoryWithValidation : createFactory,
}
2、在ReactElemene.js中通過createElement創建Element
import ReactCurrentOwner from './ReactCurrentOwner';
const ReactElement = function(type, key, ref, self, source, owner, props) {
const element = {
$$typeof: REACT_ELEMENT_TYPE,
type: type,
key: key,
ref: ref,
props: props,
_owner: owner,
};
return element;
};
export function createElement(type, config, children) {
let propName;
const props = {};
let key = null;
let ref = null;
let self = null;
let source = null;
if (config != null) {
if (hasValidRef(config)) {
ref = config.ref;
}
if (hasValidKey(config)) {
key = '' + config.key;
}
self = config.__self === undefined ? null : config.__self;
source = config.__source === undefined ? null : config.__source;
// Remaining properties are added to a new props object
for (propName in config) {
if (
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
props[propName] = config[propName];
}
}
}
const childrenLength = arguments.length - 2;
if (childrenLength === 1) {
props.children = children;
} else if (childrenLength > 1) {
const childArray = Array(childrenLength);
for (let i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
}
props.children = childArray;
}
// Resolve default props
if (type && type.defaultProps) {
const defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
// 每一個新創建的element都同時返回ReactCurrentOwner,用於跟蹤當前element
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props,
);
}
3、看到這裏就明白了,創建的元素關聯上Owner其實就是一個Fiber對象,在整個Fiber模塊裏就能發現其中的比較
import type {Fiber} from 'react-reconciler/src/ReactFiber';
const ReactCurrentOwner = {
/**
* @internal
* @type {ReactComponent}
*/
current: (null: null | Fiber),
};
export default ReactCurrentOwner;
4、ReactFiberClassComponent是否爲PureComponent,其中ctor其實就是Component
function checkShouldComponentUpdate(
workInProgress,
ctor,
oldProps,
newProps,
oldState,
newState,
nextContext,
) {
const instance = workInProgress.stateNode;
if (typeof instance.shouldComponentUpdate === 'function') {
startPhaseTimer(workInProgress, 'shouldComponentUpdate');
const shouldUpdate = instance.shouldComponentUpdate(
newProps,
newState,
nextContext,
);
stopPhaseTimer();
return shouldUpdate;
}
if (ctor.prototype && ctor.prototype.isPureReactComponent) {
return (
!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
);
}
return true;
}
四、在Fiber最終執行後體現的是在ReactDOM中。和react-reconciler關聯起來在ReactFiberBeginWork模塊中調用ReactFiberClassComponent的方法
function beginWork(
current: Fiber | null,
workInProgress: Fiber,
renderExpirationTime: ExpirationTime,
): Fiber | null {
const updateExpirationTime = workInProgress.expirationTime;
// Before entering the begin phase, clear the expiration time.
workInProgress.expirationTime = NoWork;
switch (workInProgress.tag) {
// 不確定組件,其實就是剛開始創建的組件還未指定類型
case IndeterminateComponent: {
}
// 懶加載組件
case LazyComponent: {
}
// 函數式組件
case FunctionComponent: {
}
// class組件具有什麼週期
case ClassComponent: {
const Component = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
const resolvedProps =
workInProgress.elementType === Component
? unresolvedProps
: resolveDefaultProps(Component, unresolvedProps);
return updateClassComponent(
current,
workInProgress,
Component,
resolvedProps,
renderExpirationTime,
);
}
}
}