React 源码阅读1
Fork最新版的 React 源码地址
刚开始看源码,先过一遍.先看最顶层暴露出来的 API
,再具体看实现的源码.
保持学习.
React 入口
const React = {
Children: {
map,
forEach,
count,
toArray,
only,
},
createRef,
Component,
PureComponent,
createContext,
forwardRef,
lazy,
memo,
useCallback,
useContext,
useEffect,
useImperativeHandle,
useDebugValue,
useLayoutEffect,
useMemo,
useReducer,
useRef,
useState,
Fragment: REACT_FRAGMENT_TYPE,
Profiler: REACT_PROFILER_TYPE,
StrictMode: REACT_STRICT_MODE_TYPE,
Suspense: REACT_SUSPENSE_TYPE,
unstable_SuspenseList: REACT_SUSPENSE_LIST_TYPE,
createElement: __DEV__ ? createElementWithValidation : createElement,
cloneElement: __DEV__ ? cloneElementWithValidation : cloneElement,
createFactory: __DEV__ ? createFactoryWithValidation : createFactory,
isValidElement: isValidElement,
version: ReactVersion,
unstable_withSuspenseConfig: withSuspenseConfig,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactSharedInternals,
};
export default React;
Children
React.Children
提供了用于处理 this.props.children
不透明数据结构的实用方法。
// React.js
import {forEach, map, count, toArray, only} from './ReactChildren';
...
...
Children: {
map,
forEach,
count,
toArray,
only,
},
//ReactChildren,js
export {
forEachChildren as forEach,
mapChildren as map,
countChildren as count,
onlyChild as only,
toArray,
};
React.Children.map
在 children
里的每个直接子节点上调用一个函数,并将 this
设置为 thisArg
。如果 children
是一个数组,它将被遍历并为数组中的每个子节点调用该函数。
如果子节点为null
或是 undefined
,则此方法将返回 null
或是 undefined
,而不会返回数组。
如果 children 是一个 Fragment 对象,它将被视为单一子节点的情况处理,而不会被遍历。
render() {
return (
);
}
map
源码
function mapChildren(children, func, context) {
if (children == null) {
return children;
}
// 返回 result 数组
const result = [];
//result 进去走了一圈 这边就不再细说
mapIntoWithKeyPrefixInternal(children, result, null, func, context);
return result;
}
https://segmentfault.com/a/11... 写的比较详细
React.Children.forEach
React.Children.forEach(children, function[(thisArg)])
与 React.Children.map()
类似,但它不会返回一个数组。
forEach
源码
/**
* Iterates through children that are typically specified as `props.children`.
*
* See https://reactjs.org/docs/react-api.html#reactchildrenforeach
*
* The provided forEachFunc(child, index) will be called for each
* leaf child.
*
* @param {?*} children Children tree container.
* @param {function(*, int)} forEachFunc
* @param {*} forEachContext Context for forEachContext.
*/
function forEachChildren(children, forEachFunc, forEachContext) {
if (children == null) {
return children;
}
const traverseContext = getPooledTraverseContext(
null,
null,
forEachFunc,
forEachContext,
);
traverseAllChildren(children, forEachSingleChild, traverseContext);
releaseTraverseContext(traverseContext);
}
React.Children.count
React.Children.count(children)
返回 children
中的组件总数量,等同于通过map
或 forEach
调用回调函数的次数。
count
源码
function countChildren(children) {
return traverseAllChildren(children, () => null, null);
}
React.Children.only
React.Children.only(children)
验证 children
是否只有一个子节点(一个 React
元素),如果有则返回它,否则此方法会抛出错误。
only
源码
function onlyChild(children) {
invariant(
isValidElement(children),
'React.Children.only expected to receive a single React element child.',
);
return children;
}
React.Children.only()
不接受React.Children.map()
的返回值,因为它是一个数组而并不是React
元素。
React.Children.toArray
React.Children.toArray(children)
将 children
这个复杂的数据结构以数组的方式扁平展开并返回,并为每个子节点分配一个 key
。
当你想要在渲染函数中操作子节点的集合时,它会非常实用,特别是当你想要在向下传递 this.props.children
之前对内容重新排序或获取子集时。
React.Children.toArray()
在拉平展开子节点列表时,更改 key
值以保留嵌套数组的语义。
也就是说,toArray
会为返回数组中的每个 key
添加前缀,以使得每个元素 key
的范围都限定在此函数入参数组的对象内。
toArray
源码
function toArray(children) {
const result = [];
mapIntoWithKeyPrefixInternal(children, result, null, child => child);
return result;
}