旧版本中的 render 方法只做了一件事,就是调起 diff 方法,新版本中的 render 引入了 Fragment ,让我们写的自定义组件都成了子组件。
React.Fragment
Fragment 就是让 react 组件能够聚合一个个子元素列表,那样就不必要在增加一个额外的节点了
// 旧的写法
render(){
return (
<div>
<ChildA />
<ChildB />
<ChildC />
</div>
)
}
// Fragment
render(){
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
)
}
<></> 其实是 <React.Fragment/> 的语法糖,当组件中需要遍历数组传递 key 值时,就需要使用 <React.Fragment/>
render(){
return (
<div>
{
goodsList.map(item => (
<React.Fragment key={item.id}>
<p>{item.goodsName}</p>
</React.Fragment>
))
}
</div>
)
}
了解了 react 的 Fragment ,那 preact 是如何使用和实现的呢:
使用:
import {h, render, Component, Fragment} from 'preact';
class App extends Component {
render(){
return (
<Fragment>
<div>preact</div>
<div>使用了Fragment</div>
</Fragment>
)
}
}
在 preact 中,并没有类似 <></> 这样的语法糖,下面来看下它的实现原理:
function Fragment() {}
function render(vnode, parentDom, replaceNode) {
// ...
vnode = createElement(Fragment, null, [vnode]);
// ...
}
在 render 方法中调用了 createElement 方法创建了一个虚拟 dom ,第一个参数就是 Fragment ,实参是一个 function。createElement 这个函数的第一个形参 type 是这个虚拟 dom 的类型,它有可能是 div,span 等,也有可能是一个 function,当讲到 diff 时,会专门有一个分支就是判断 type === Fragment 的情况,那个时候再细讲,这里只简单说下结果:
Fragment作为虚拟dom的类型传入,在diff一个组件时,时如果遇到type === Fragment时,就直接diff<Fragment></Fragment>包裹的子节点,而这些子节点所渲染的真实dom会直接挂载在<Fragment></Fragment>所对应的父节点上。
以上就是 Fragment 的简单实现,在 render 方法中,通过 createElement 方法重新创建的 vnode 会传入 diffChildren 方法中,这个方法是整个新版中最核心的方法,将在后面专门会说这个方法,这里可以简单的理解为--对比这个 vnode 下的子节点是否更新。
在这个 render 方法中,由于最外层包裹的是一个 Fragment ,所以,这里的 diffChildren 比对的对象就是 Fragment 包裹下的子节点。
下一章,我们就来看看这个 diffChildren 方法。