我们都知道组件是有模版、组件描述对象、数据构成的,数据的变化会引起组件的更新。组件的渲染过程中创建了一个带副作用的渲染函数,当数据发生变化的时候,就会执行这个渲染函数,触发组件的更新。
副作用渲染函数更新组件的过程
副作用渲染函数是setupRenderEffect:
const setupRenderEffect = (instance, initialVNode, container, anchor, parentSuspense, isSVG, optimized) => {
instance.update = effect(function componentEffect() {
if (!instance.isMounted) {
...
}
else {
let { next, bu, u, parent, vnode } = instance;
let originNext = next;
let vnodeHook;
{
pushWarningContext(next || instance.vnode);
}
if (next) {
next.el = vnode.el;
updateComponentPreRender(instance, next, optimized);
}
else {
next = vnode;
}
...
const nextTree = renderComponentRoot(instance);
{
endMeasure(instance, `render`);
}
const prevTree = instance.subTree;
instance.subTree = nextTree;
{
startMeasure(instance, `patch`);
}
patch(prevTree, nextTree,
// parent may have changed if it's in a teleport
hostParentNode(prevTree.el),
// anchor may have changed if it's in a fragment
getNextHostNode(prevTree), instance, parentSuspense, isSVG);
{
endMeasure(instance, `patch`);
}
...
}
}
}
这代码大概的意思,我的理解是:如果组件没有渲染过!instance.isMounted,那就渲染,如果不是,else执行的是更新组件。
if (next) {
next.el = vnode.el;
updateComponentPreRender(instance, next, optimized);
}
next表示新的组件vnode,updateComponentPreRender函数是更新组件vnode节点信息。
const nextTree = renderComponentRoot(instance);
这是渲染新的子树vnode。
const prevTree = instance.subTree;
这是缓存旧的子树vnode。之后调用patch的方法,这个是更新组件的核心逻辑。
因此,更新组件主要做了三件事:更新组件vnode节点、渲染新的子树vnode、根据新旧子树vnode执行patch逻辑。