Block Tree in Vue3
Vue3 中通过编译找到静态节点实现了 Block Tree 的优化,想在 React 中实现当然不能想编译,要想 runtime,所以我们来看看 runtime-core 源码中的是怎样渲染静态节点的:
const patch: PatchFn = (
n1,
n2,
container,
anchor = null,
parentComponent = null,
parentSuspense = null,
isSVG = false,
optimized = false
) => {
// ...
const { type, ref, shapeFlag } = n2
switch (type) {
// ...
case Static:
if (n1 == null) {
mountStaticNode(n2, container, anchor, isSVG)
} else if (__DEV__) {
patchStaticNode(n1, n2, container, isSVG)
}
break
// ...
}
patch 是一个入口,针对 type 不同进行渲染,Static 节点通过 mountStaticNode 进行 mount,如果是开发环境为了实现热更新需要进行 update
const mountStaticNode = (
n2: VNode,
container: RendererElement,
anchor: RendererNode | null,
isSVG: boolean
) => {
// static nodes are only present when used with compiler-dom/runtime-dom
// which guarantees presence of hostInsertStaticContent.
;[n2.el, n2.anchor] = hostInsertStaticContent!(
n2.children as string,
container,
anchor,
isSVG
)
}
/**
* Dev / HMR only
*/
const patchStaticNode = (
n1: VNode,
n2: VNode,
container: RendererElement,
isSVG: boolean
) => {
// static nodes are only patched during dev for HMR
if (n2.children !== n1.children) {
const anchor = hostNextSibling(n1.anchor!)
// remove existing
removeStaticNode(n1)
// insert new
;[n2.el, n2.anchor] = hostInsertStaticContent!(
n2.children as string,
container,
anchor,
isSVG
)
} else {
n2.el = n1.el
n2.anchor = n1.anchor
}
}
这就相当于直接跳过了静态节点的更新,放到 React 中可以实现吗?
Block Tree in React
当然可以!通过 shouldComponentUpdate 跳过更新,我们可以写一个 Static 组件,其 shouldComponentUpdate 始终返回 false,跳过它和它子节点的更新
export default class Static extends React.Component {
shouldComponentUpdate() {
return false
}
render() {
return this.props.children
}
}
使用的时候就可以这样:
export default function App() {
const [count, setCount] = useState(0)
return (
<div>
<Static>
<h1>Static Title</h1>
</Static>
<div>{count}</div>
<button onClick={() => setCount(count + 1)}>add one!</button>
</div>
)
}
实现 Block Tree 以减少不必要的更新
Difference
当然这样对于 Vue3 在编译时做的事交给用户来做,用户增加了心智负担,而且代码还乱,得不偿失,非常不建议这样使用 React,但这种方式我们也可以看到其实非常符合 React 的风格 🐶
好了,第一次写水 b 文章,就这样吧~