本文记录一些react17.0.2源码学习过程中的一些知识。
入口目录
-
react-main
-
packages
-
react
- index.js
-
-
1. React.Component 和 React.PureComponent
-
所在目录
-
react-main
-
packages
-
react
-
src
-
ReactBaseClasses.js
-
-
-
-
-
-
定义
Component
/**
* Base class helpers for the updating state of a 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.
this.refs = emptyObject;
// We initialize the default updater but the real one gets injected by the
// renderer.
this.updater = updater || ReactNoopUpdateQueue;
}
isReactComponent
判断是否是React的Component
Component.prototype.isReactComponent = {};
- 定义
setState
函数
参数partialState可以是object,也可以是function,最后通过updater.enqueueSetState执行回调函数callback。
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');
};
- 定义
forceUpdate
函数
redux状态管理中的state发生改变,通过 forceUpdate 函数强制对页面的进行render。
Component.prototype.forceUpdate = function(callback) {
this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};
- 定义
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;
}
- Component和PureComponent的关系
创建一个ComponentDummy类,Component原型赋值给ComponentDummy原型
PureComponent原型继承自ComponentDummy的实例,即new ComponentDummy()
因此,PureComponent类是通过原型式继承自Component类
PureComponent内置了shouldComponentUpdate生命周期。
function ComponentDummy() {}
ComponentDummy.prototype = Component.prototype;
const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
pureComponentPrototype.constructor = PureComponent;
Object.assign(pureComponentPrototype, Component.prototype);
pureComponentPrototype.isPureReactComponent = true;
2. React.createElement & React.createFactory & React.cloneElement & React.isValidElement
-
所在目录
-
react-main
-
packages
-
react
-
src
- ReactElement.js
-
-
-
-
-
ReactElement
用来处理传入进来的元素的各个属性,拼装输出一个React元素
const ReactElement = function(type, key, ref, self, source, owner, props) {
const element = {
// $$typeof为 symbolFor('react.element') 用来识别当前元素是React元素
$$typeof: REACT_ELEMENT_TYPE,
type: type, // type为标签类型 div, p 等
key: key, // 用来调和DOM Diff
// createElement的第二个参数 props => { id: 1, text: 'test' } 作为属性加到创建出来的React元素上
props: props,
_owner: owner,
}
if (__DEV__) { // 开发环境下
element._store = {}; // 特殊情况下做一个备份
Object.defineProperty(element._store, 'validated', {
configurable: false,
enumerable: false,
writable: true,
value: false,
});
// self and source are DEV only properties.
Object.defineProperty(element, '_self', {
configurable: false,
enumerable: false,
writable: false,
value: self,
});
// Two elements created in two different places should be considered
// equal for testing purposes and therefore we hide it from enumeration.
Object.defineProperty(element, '_source', {
configurable: false,
enumerable: false,
writable: false,
value: source,
});
if (Object.freeze) {
Object.freeze(element.props);
Object.freeze(element);
}
}
return element;
}
createElement
用来生成React元素
/**
* Create and return a new ReactElement of the given type.
*/
export function createElement(type, config, children) {
let propName;
// Reserved names are extracted
const props = {};
let key = null;
let ref = null;
let self = null;
let source = null;
// 传入createElement的属性不为空
if (config != null) {
// 传入的属性中有有效的Ref
if (hasValidRef(config)) {
ref = config.ref;
if (__DEV__) {
warnIfStringRefCannotBeAutoConverted(config);
}
}
// 传入的属性有有效的Key,存到key上
if (hasValidKey(config)) {
key = '' + config.key;
}
self = config.__self === undefined ? null : config.__self;
source = config.__source === undefined ? null : config.__source;
for (propName in config) {
if (
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
props[propName] = config[propName];
}
}
}
// Children可能是多个参数
const childrenLength = arguments.length - 2;
if (childrenLength === 1) {
props.children = children; // children会放到props上
} else if (childrenLength > 1) {
const childArray = Array(childrenLength);
for (let i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
}
props.children = childArray;
}
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props,
);
}
最终输出的JS对象element
{
$$typeof: symbolFor('react.element'), // React元素标识
key: config.key, // key属性用来调和diff
ref: config.ref, // ref属性用来获取渲染后的DOM节点
props: {
children: {} // {} | [],
... // 以及传入飞config中所有的属性
},
type: 'div', // 元素类型
_owner: null, // 谁负责创建出这个元素,默认为Fiber
_store: null, // dev环境下的做的备份
_self: null,
_source: null
}
createFactory
创建一个type类型的factory方法
/**
* Return a function that produces ReactElements of a given type.
*/
export function createFactory(type) {
const factory = createElement.bind(null, type);
// Expose the type on the factory and the prototype so that it can be
// easily accessed on elements. E.g. `<Foo />.type === Foo`.
// This should not be named `constructor` since this may not be the function
// that created the element, and it may not even be a constructor.
// Legacy hook: remove it
factory.type = type;
return factory;
}
cloneElement
使用元素作为起点克隆并且返回一个新的ReactElement
/**
* Clone and return a new ReactElement using element as the starting point.
* See https://reactjs.org/docs/react-api.html#cloneelement
*/
export function cloneElement(element, config, children) {
}
isValidElement
用来验证一个对象是否是有效的ReactElement元素
/**
* Verifies the object is a ReactElement.
*/
export function isValidElement(object) {
return (
typeof object === 'object' &&
object !== null &&
object.$$typeof === REACT_ELEMENT_TYPE
);
}
3. React.Children
- React.children 是react提供的一个处理
this.props.children
的方法,无论this.props.chilren是undefined
,object
(一个child),array
(多个child),都不用担心,它都做了兼容的处理,直接传入React.Children方法中即可返回出React的节点。
<script type="text/jsx">
var List = React.createClass({
render: function() {
return (
<ul>
{
React.Children.map(this.props.children, function (child) {
return <li>{child}</li>;
})
}
</ul>
);
}
});
React.render(
<List>
<span>hello</span>
<span>world</span>
</List>,
document.body
);
</script>
-
React.Children.map
遍历 this.props.children 返回HTML结构 -
React.Children.forEach
遍历 this.props.children 没有返回值 -
React.Children.count
返回 this.props.children 子元素总和
<List>
<span>hello</span>
<span>world</span>
</List>
console.log(React.Children.count(this.props.children)); // 2
<List></List>
console.log(React.Children.count(this.props.children)); // 0
<List>null</List>
console.log(React.Children.count(this.props.children)); // 1
-
React.Children.only
-
返回 this.props.children 中
仅有的子级
。否则抛出异常。 -
这里仅有的子级,only方法接受的参数只能是一个对象,不能是多个对象(数组)。
-
4. React.createRef
-
所在目录
-
react-main
-
packages
-
react
-
src
- ReactCreateRef.js
-
-
-
-
-
createRef
创建一个引用对象,引用对象是父组件的成员,父组件可以通过引用对象操作子组件
// an immutable object with a single mutable value
export function createRef(): RefObject {
const refObject = {
current: null,
};
if (__DEV__) { // 将对象密封(不能增删属性、配置属性,但可以给属性赋值)
Object.seal(refObject);
}
return refObject;
}
5. React.createContext
createContext
创建一个上下文,该context对象有 Provide 和 Consumer 属性
export function createContext<T>(defaultValue: T): ReactContext<T> {
const context: ReactContext<T> = {
$$typeof: REACT_CONTEXT_TYPE,
_currentValue: defaultValue,
_currentValue2: defaultValue,
_threadCount: 0,
Provider: (null: any),
Consumer: (null: any),
};
context.Provider = {
$$typeof: REACT_PROVIDER_TYPE,
_context: context,
};
let hasWarnedAboutUsingNestedContextConsumers = false;
let hasWarnedAboutUsingConsumerProvider = false;
let hasWarnedAboutDisplayNameOnConsumer = false;
if (__DEV__) {
const Consumer = {
$$typeof: REACT_CONTEXT_TYPE,
_context: context,
};
Object.defineProperties(Consumer, {
Provider: {
get() {
if (!hasWarnedAboutUsingConsumerProvider) {
hasWarnedAboutUsingConsumerProvider = true;
return context.Provider;
},
set(_Provider) {
context.Provider = _Provider;
},
},
_currentValue: {
get() {
return context._currentValue;
},
set(_currentValue) {
context._currentValue = _currentValue;
},
},
_currentValue2: {
get() {
return context._currentValue2;
},
set(_currentValue2) {
context._currentValue2 = _currentValue2;
},
},
_threadCount: {
get() {
return context._threadCount;
},
set(_threadCount) {
context._threadCount = _threadCount;
},
},
Consumer: {
get() {
if (!hasWarnedAboutUsingNestedContextConsumers) {
hasWarnedAboutUsingNestedContextConsumers = true;
}
return context.Consumer;
},
},
displayName: {
get() {
return context.displayName;
},
set(displayName) {
if (!hasWarnedAboutDisplayNameOnConsumer) {
hasWarnedAboutDisplayNameOnConsumer = true;
}
},
},
});
context.Consumer = Consumer;
} else {
context.Consumer = context;
}
if (__DEV__) {
context._currentRenderer = null;
context._currentRenderer2 = null;
}
return context;
}