Skip to content

Commit

Permalink
feat: add component update detection logic
Browse files Browse the repository at this point in the history
  • Loading branch information
cuixiaorui committed Mar 3, 2021
1 parent fc6803c commit 6c4dff9
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 2 deletions.
46 changes: 46 additions & 0 deletions src/runtime-core/componentRenderUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
export function shouldUpdateComponent(prevVNode, nextVNode) {
const { props: prevProps } = prevVNode;
const { props: nextProps } = nextVNode;
// todo ?? 不知道是什么
// const emits = component!.emitsOptions;

// 这里主要是检测组件的 props
// 核心:只要是 props 发生改变了,那么这个 component 就需要更新

// 1. props 没有变化,那么不需要更新
if (prevProps === nextProps) {
return false;
}
// 如果之前没有 props,那么就需要看看现在有没有 props 了
// 所以这里基于 nextProps 的值来决定是否更新
if (!prevProps) {
return !!nextProps;
}
// 之前有值,现在没值,那么肯定需要更新
if (!nextProps) {
return true;
}

// 以上都是比较明显的可以知道 props 是否是变化的
// 在 hasPropsChanged 会做更细致的对比检测
return hasPropsChanged(prevProps, nextProps);
}

function hasPropsChanged(prevProps, nextProps): boolean {
// 依次对比每一个 props.key

// 提前对比一下 length ,length 不一致肯定是需要更新的
const nextKeys = Object.keys(nextProps);
if (nextKeys.length !== Object.keys(prevProps).length) {
return true;
}

// 只要现在的 prop 和之前的 prop 不一样那么就需要更新
for (let i = 0; i < nextKeys.length; i++) {
const key = nextKeys[i];
if (nextProps[key] !== prevProps[key]) {
return true;
}
}
return false;
}
24 changes: 22 additions & 2 deletions src/runtime-core/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { queueJob } from "./scheduler";
import { effect } from "@vue/reactivity";
import { setupComponent } from "./component";
import { Text } from "./vnode";
import { h } from "./h";
import { shouldUpdateComponent } from "./componentRenderUtils";

export const render = (vnode, container) => {
console.log("调用 patch");
Expand Down Expand Up @@ -346,8 +346,28 @@ function processComponent(n1, n2, container, parentComponent) {

// 组件的更新
function updateComponent(n1, n2, container) {
// TODO
console.log("更新组件", n1, n2);
// 更新组件实例引用
const instance = (n2.component = n1.component);
// 先看看这个组件是否应该更新
if (shouldUpdateComponent(n1, n2)) {
console.log(`组件需要更新: ${instance}`);
// 那么 next 就是新的 vnode 了(也就是 n2)
instance.next = n2;
// 这里的 update 是在 setupRenderEffect 里面的 init 的,update 函数除了当内部的响应式对象发生改变的时候会调用
// 还可以直接主动的调用(这是属于 effect 的特性)
// 调用 update 再次更新调用 patch 逻辑
// 在update 中调用的 next 就变成了 n2了
// ps:可以详细的看看 update 中 next 的应用
// TODO 需要在 update 中处理支持 next 的逻辑
// instance.update();
} else {
console.log(`组件不需要更新: ${instance}`);
// 不需要更新的话,那么只需要覆盖下面的属性即可
n2.component = n1.component;
n2.el = n1.el;
instance.vnode = n2;
}
}

function mountComponent(initialVNode, container, parentComponent) {
Expand Down

0 comments on commit 6c4dff9

Please sign in to comment.