React 版本为 16.8.6(直接看打包后的文件,源代码中文件很分散,建议熟悉流程后在去阅读打包前的代码)
一、
React.createElement:JSX 代码会被 Babel 编译为 React.createElement
react.development.js(line:762)此函数返回createElement包装后的对象
createElement 函数接收 3 个参数,分别是 type, config, children, type 指的是 ReactElement 的类型
1.字符串 div 或 p 等代表原生 DOM,称为 HostComponent;
2.class 类型继承 Component 或 PureComponent 组件的称为 ClassComponent; 方法就是 FunctionalComponent;
3.原生提供的 Fragment、AsyncMode 等是 Symbol,会特殊处理;
4.其他;
function createElement(type, config, children) {
var propName = void 0;
// Reserved names are extracted
var props = {};
var key = null;
var ref = null;
var self = null;
var source = null;
if (config != null) {
// 判断是否有ref属性且ref属性有值 单独取出来
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;
// 把剩余的属性塞到props里面
for (propName in config) {
//严谨的判断config对象中是否存在改属性,且属性名不能是react保留的那四种
if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
props[propName] = config[propName];
}
}
}
// children 的个数
var childrenLength = arguments.length - 2;
if (childrenLength === 1) {
props.children = children;
} else if (childrenLength > 1) {
//多个孩子 包装成一个数组 挂载到props
var childArray = Array(childrenLength);
for (var i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
}
props.children = childArray;
}
// 如果type传的东西是个对象,且type有defaultProps这个东西,那就defaultProps的值也塞props里面
if (type && type.defaultProps) {
var defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);
}
react.development.js(line:296)
updater 在 react-dom 中创建
function Component(props, context, updater) {
this.props = props;
this.context = context;
this.refs = emptyObject;
this.updater = updater || ReactNoopUpdateQueue;
}
Component.prototype.isReactComponent = {};
Component.prototype.setState = function (partialState, callback) {
!(typeof partialState === 'object' || typeof partialState === 'function' || partialState == null) ? invariant(false, 'setState(...): takes an object of state variables to update or a function which returns an object of state variables.') : void 0;
this.updater.enqueueSetState(this, partialState, callback, 'setState');
};
Component.prototype.forceUpdate = function (callback) {
this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};
function ComponentDummy() {}
ComponentDummy.prototype = Component.prototype;
function PureComponent(props, context, updater) {
this.props = props;
this.context = context;
this.refs = emptyObject;
this.updater = updater || ReactNoopUpdateQueue;
}
//经典的继承方式 只保留原型上的方法
var pureComponentPrototype = PureComponent.prototype = new ComponentDummy();
pureComponentPrototype.constructor = PureComponent;
// 属性拷贝 猜测这里是确保兼容性 (不确定)
_assign(pureComponentPrototype, Component.prototype);
pureComponentPrototype.isPureReactComponent = true;
createRef更简单
function createRef() {
var refObject = {
current: null
};
{
Object.seal(refObject);
}
return refObject;
}
forwardRef:
var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;
function forwardRef(render) {
return {
$$typeof: REACT_FORWARD_REF_TYPE,
render: render
};
}
react.development.js(line:1199)
ReactChildren:
[item, [item, [item]]]经过map()后,平铺成[item,item,item]
function mapChildren(children, func, context) {
//孩子不存在就返回一个null
if (children == null) {
return children;
}
var result = [];
//参数:props.children, [], null, (item)=>{return [item,[item,] ]}, undefined 回调函数由用户传入自定义的
mapIntoWithKeyPrefixInternal(children, result, null, func, context);
//经过上面的函数处理,返回出最终渲染的东西
return result;
}
function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) {
var escapedPrefix = '';
//如果字符串中有连续多个 / 的话,在匹配的字串后再加 / 第二次进入这个函数会用到
if (prefix != null) {
escapedPrefix = escapeUserProvidedKey(prefix) + '/';
}
var traverseContext = getPooledTraverseContext(array, escapedPrefix, func, context);
traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
releaseTraverseContext(traverseContext);
}
先从对象池中取数据getPooledTraverseContext
//对象池
var POOL_SIZE = 10;
var traverseContextPool = [];
function getPooledTraverseContext(mapResult, keyPrefix, mapFunction, mapContext) {
//如果对象池内存在对象,则出队一个对象
if (traverseContextPool.length) {
var traverseContext = traverseContextPool.pop();
traverseContext.result = mapResult;
traverseContext.keyPrefix = keyPrefix;
traverseContext.func = mapFunction;
traverseContext.context = mapContext;
traverseContext.count = 0;
return traverseContext;
} else {
//如果不存在,则返回一个新对象
return {
result: mapResult,
keyPrefix: keyPrefix,
func: mapFunction,
context: mapContext,
count: 0
};
}
}
mapSingleChildIntoContext:
//bookKeeping:traverseContext=
// {
// result:[],
// keyPrefix:'',
// func:(item)=>{return [item,[item,] ]},
// context:undefined,
// count:0,
// }
//child:1
//childKey:.0
function mapSingleChildIntoContext(bookKeeping, child, childKey) {
var result = bookKeeping.result,
keyPrefix = bookKeeping.keyPrefix,
func = bookKeeping.func,
context = bookKeeping.context;
// func ----> React.Children.map(this.props.children, '----->代表这个函数func' (item)=>{return [item,[item,] ]})
var mappedChild = func.call(context, child, bookKeeping.count++);
//如果根据React.Children.map()第二个参数callback,执行仍是一个数组的话,
//递归调用mapIntoWithKeyPrefixInternal,继续之前的步骤,
//直到是单个ReactElement
if (Array.isArray(mappedChild)) {
//mappedChild:[item,[item,] ]
//result:[]
//childKey:.0
//func:c => c
mapIntoWithKeyPrefixInternal(mappedChild, result, childKey, function (c) {
return c;
});
} else if (mappedChild != null) { //当mappedChild是单个ReactElement并且不为null的时候
if (isValidElement(mappedChild)) {
//赋给新对象除key外同样的属性,替换key属性
mappedChild = cloneAndReplaceKey(mappedChild,
// Keep both the (mapped) and old keys if they differ, just as
// traverseAllChildren used to do for objects as children
keyPrefix + (mappedChild.key && (!child || child.key !== mappedChild.key) ? escapeUserProvidedKey(mappedChild.key) + '/' : '') + childKey);
}
result.push(mappedChild);
}
}
traverseAllChildren–> traverseAllChildrenImpl(line:1066):
核心递归函数,目的是展平嵌套数组
function traverseAllChildrenImpl(children, nameSoFar, callback, traverseContext) {
var type = typeof children;
if (type === 'undefined' || type === 'boolean') {
// All of the above are perceived as null.
children = null;
}
var invokeCallback = false;
if (children === null) {
invokeCallback = true;
} else {
switch (type) {
case 'string':
case 'number':
invokeCallback = true;
break;
case 'object':
//如果props.children是单个ReactElement/PortalElement的话
//递归traverseAllChildrenImpl时,1和2作为child
//必会触发invokeCallback=true
switch (children.$$typeof) {
case REACT_ELEMENT_TYPE:
case REACT_PORTAL_TYPE:
invokeCallback = true;
}
}
}
if (invokeCallback) {
// callback ---> mapSingleChildIntoContext
callback(traverseContext, children,
// If it's the only child, treat the name as if it was wrapped in an array
// so that it's consistent if the number of children grows.
//如果只有一个子节点,也将它放在数组中来处理
//1 key='.0'
nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar);
return 1; //下面有 subtreeCount += .....
}
var child = void 0;
var nextName = void 0;
//有多少个子节点
var subtreeCount = 0; // Count of children found in the current subtree.
var nextNamePrefix = nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR;
if (Array.isArray(children)) {
for (var i = 0; i < children.length; i++) {
child = children[i];
nextName = nextNamePrefix + getComponentKey(child, i);
//递归调用
subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
}
} else {
//判断child是否可迭代
var iteratorFn = getIteratorFn(children);
if (typeof iteratorFn === 'function') {
var iterator = iteratorFn.call(children);
var step = void 0;
var ii = 0;
while (!(step = iterator.next()).done) {
child = step.value;
nextName = nextNamePrefix + getComponentKey(child, ii++);
subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
}
} else if (type === 'object') {
...一些错误警告
}
}
return subtreeCount;
}