文章目录
React.Children.map
先来看这样一段代码:
import React from 'react';
function Father(props){
console.log(props.children);
console.log(React.Children.map(props.children, item=>[item, item]));
return props.children;
}
export default () => (
<Father>
<div>hello</div>
<div>hello</div>
<div>hello</div>
</Father>
);
代码很简单,在页面上只是显示了三行"hello"而已。重点不在这里,而是在于通过console.log
在控制台输出的内容。
我们知道可以通过组件的props.children
获得该组件的子组件。那么可以想到console.log(props.children);
预期的结果应该是打印出一个长度为3的数组。
事实也确实如此,控制台中输出了一个长度为3的ReactElement
数组。
那么console.log(React.Children.map(props.children, item=>[item, item]));
会在控制台输出什么呢?
我们可能会猜想它应该与数组的map
方法一样,返回一个长度为3的二维数组,每个元素又是一个长度为2的ReactElement
数组。
可事实却并不是这样,控制台输出的是一个长度为6的ReactElement
数组。可以想见,React.map
将我们设想中的二维数组给降维了。
具体过程是怎样,需要看看源码。
源码阅读
React.js
首先在源码目录下的React.js
可以发现map
是在此处成为React.Children
的一个方法的。
接着可以发现它真正的定义是在同目录下的ReactChildren.js
文件中。
ReactChildren.js
在ReactChildren.js
文件的最尾部,可以看到map
方法在此处被导出,其真正的名字应该是mapChildren
。
mapChildren()
function mapChildren(children, func, context) {
if (children == null) {
return children;
}
const result = [];
mapIntoWithKeyPrefixInternal(children, result, null, func, context);
return result;
}
这个方法接受3个参数children
、func
和context
。
children
就是将要被遍历的子组件数组,func
是对单个子组件需要执行的函数,context
则是func
执行时this
指针所指向的对象。
mapIntoWithKeyPrefixInternal()
function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) {
let escapedPrefix = '';
if (prefix != null) {
escapedPrefix = escapeUserProvidedKey(prefix) + '/';
}
const traverseContext = getPooledTraverseContext(
array,
escapedPrefix,
func,
context,
);
traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
releaseTraverseContext(traverseContext);
}
这个方法本