源码
最近看 React 源码的时候发现其在处理数组的同时也对可迭代协议做了处理,因此 React 组件可以是一个返回可迭代对象的函数。源码如下:
reconcileChildFibersImpl
if (isArray(newChild)) {
return reconcileChildrenArray(returnFiber, currentFirstChild, newChild, lanes, mergeDebugInfo(debugInfo, newChild._debugInfo));
}
if (getIteratorFn(newChild)) {
return reconcileChildrenIterator(returnFiber, currentFirstChild, newChild, lanes, mergeDebugInfo(debugInfo, newChild._debugInfo));
}
getIteratorFn
var MAYBE_ITERATOR_SYMBOL = Symbol.iterator;
var FAUX_ITERATOR_SYMBOL = '@@iterator';
function getIteratorFn(maybeIterable) {
if (maybeIterable === null || typeof maybeIterable !== 'object') {
return null;
}
var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];
if (typeof maybeIterator === 'function') {
return maybeIterator;
}
return null;
}
可以看到 React 会判断 newChild
是否可迭代——通过 Symbol.iterator
和 @@iterator
属性。
现在我们可以构造一个这样的组件了:
function IteratorComponent() {
return {
[Symbol.iterator]() {
return {
n: 0,
next() {
const tag = "h" + ++this.n;
return {
value: React.createElement(tag, {
key: tag
}, this.n),
done: this.n > 4,
};
},
};
},
};
}
上述组件最终会渲染出 4 个 h{n}
标签。
注意事项
- React 虽然支持可迭代协议,但是并不支持
generator
。 - 因为 React 会多次渲染或者会校验迭代器值的情况,对象中的
Symbol.iterator
函数必须是纯函数,即每次调用都是返回一个新的迭代器。