舊版本中的 render
方法只做了一件事,就是調(diào)起 diff
方法惩阶,新版本中的 render
引入了 Fragment
挎狸,讓我們寫的自定義組件都成了子組件。
React.Fragment
Fragment
就是讓 react
組件能夠聚合一個(gè)個(gè)子元素列表断楷,那樣就不必要在增加一個(gè)額外的節(jié)點(diǎn)了
// 舊的寫法
render(){
return (
<div>
<ChildA />
<ChildB />
<ChildC />
</div>
)
}
// Fragment
render(){
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
)
}
<></>
其實(shí)是 <React.Fragment/>
的語法糖锨匆,當(dāng)組件中需要遍歷數(shù)組傳遞 key
值時(shí),就需要使用 <React.Fragment/>
render(){
return (
<div>
{
goodsList.map(item => (
<React.Fragment key={item.id}>
<p>{item.goodsName}</p>
</React.Fragment>
))
}
</div>
)
}
了解了 react
的 Fragment
冬筒,那 preact
是如何使用和實(shí)現(xiàn)的呢:
使用:
import {h, render, Component, Fragment} from 'preact';
class App extends Component {
render(){
return (
<Fragment>
<div>preact</div>
<div>使用了Fragment</div>
</Fragment>
)
}
}
在 preact
中恐锣,并沒有類似 <></>
這樣的語法糖,下面來看下它的實(shí)現(xiàn)原理:
function Fragment() {}
function render(vnode, parentDom, replaceNode) {
// ...
vnode = createElement(Fragment, null, [vnode]);
// ...
}
在 render
方法中調(diào)用了 createElement
方法創(chuàng)建了一個(gè)虛擬 dom
舞痰,第一個(gè)參數(shù)就是 Fragment
土榴,實(shí)參是一個(gè) function
。createElement
這個(gè)函數(shù)的第一個(gè)形參 type
是這個(gè)虛擬 dom
的類型响牛,它有可能是 div,span
等玷禽,也有可能是一個(gè) function
,當(dāng)講到 diff
時(shí)呀打,會(huì)專門有一個(gè)分支就是判斷 type === Fragment
的情況矢赁,那個(gè)時(shí)候再細(xì)講,這里只簡單說下結(jié)果:
Fragment
作為虛擬dom的類型傳入贬丛,在diff
一個(gè)組件時(shí)撩银,時(shí)如果遇到type === Fragment
時(shí),就直接diff
<Fragment></Fragment>
包裹的子節(jié)點(diǎn)豺憔,而這些子節(jié)點(diǎn)所渲染的真實(shí)dom
會(huì)直接掛載在<Fragment></Fragment>
所對應(yīng)的父節(jié)點(diǎn)上额获。
以上就是 Fragment
的簡單實(shí)現(xiàn),在 render
方法中焕阿,通過 createElement
方法重新創(chuàng)建的 vnode
會(huì)傳入 diffChildren
方法中咪啡,這個(gè)方法是整個(gè)新版中最核心的方法,將在后面專門會(huì)說這個(gè)方法暮屡,這里可以簡單的理解為--對比這個(gè) vnode
下的子節(jié)點(diǎn)是否更新撤摸。
在這個(gè) render
方法中,由于最外層包裹的是一個(gè) Fragment
褒纲,所以准夷,這里的 diffChildren
比對的對象就是 Fragment
包裹下的子節(jié)點(diǎn)。
下一章莺掠,我們就來看看這個(gè) diffChildren
方法衫嵌。