这一篇是解析
packages/react/ReactBaseClasses.js
的源码的
像文件名说的那样,这个文件主要定义了Component、PureComponent 这两个基础类;
Component
Component类主要实现了以下两个原型链的方法:setState
和forceUpdate
,这两个方法的背后是基于updater
去实现的(如果没有正确实例化并被挂载时会用ReactNoopUpdateQueue
去实现);
ReactNoopUpdateQueue
的处理行为就是针对enqueueSetState
和enqueueForceUpdate
去给出警告,告诉开发者,这里可能会有潜在的bug
以下是他们的源代码:
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');
};
Component.prototype.forceUpdate = function(callback) {
this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};
然后比较关键的处理行为:
在开发模式下会针对两个deprecatedAPIs
:isMounted
、replaceState
去做get时候的警告:
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]);
}
}
}
PureComponent基类的实现
PureComponent
的实现是通过ComponentDummy
这个中间类去实现的;
ComponentDummy
的作用就是断开对于Component.prototype
的引用,这样在修改PureComponent
的原型链方法的时候不会对Component
造成影响,同时为了避免原型链的跳跃,做了一个Object.assign(pureComponentPrototype, Component.prototype);
的处理。
function ComponentDummy() {}
ComponentDummy.prototype = Component.prototype;
/**
* Convenience component with default shallow equality check for sCU.
*/
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());
pureComponentPrototype.constructor = PureComponent;
// Avoid an extra prototype jump for these methods.
Object.assign(pureComponentPrototype, Component.prototype);
pureComponentPrototype.isPureReactComponent = true;