Vue3源码:computed

181 阅读1分钟

三个阶段\

以下面代码为例:\

<script setup>
import {ref, computed} from "vue";
let aaa = ref(100);
function Num() {
  aaa.value++
}
let acomputed = computed(() => {
  return `computed:` + aaa.value
})
</script>

<template>
  <div class="wrapper">
    <div v-on:click="Num">Father</div>
    <p>{{ acomputed }}</p>
  </div>
</template>

打包在内存中的vue文件(只截了template部分): image.png

一、定义阶段

通过computed函数进入,getter即定义comNumber时的入参,创建ComputedRefImpl实例的时候也会创建一个ReactiveEffect实例(计算属性effect),后续执行render的过程也会创建响应式的ReactiveEffect实例(响应式effect) 569F6F09-50F9-4dad-A5B2-5D39ECA5C441.png

二、收集阶段

执行_sfc_render过程访问到$setup.acomputed(即我们创建的ComputedRefImpl实例),触发get value
run()函数指向的是computed实例的getter也是我们定义acomputed是入参的函数,此函数执行的时候会获取计算属性的结果 image.png

执行trackEffect函数(入参的activeEffect是 响应式effect),把 响应式effect放在ref2.dep中(ref2即acomputed),

image.png

三、触发阶段

执行aaa.value++的时候触发aaa实例的set value,拿到aaa.dep(保存的是计算属性effect),执行effect.trigger()(acomputed.dep中存的是响应式effect)会把响应式函数update放在队列里后面触发更新
更新的时候会执行sfc_render重新生成vnode,此过程会再次访问$setup.acomputed,重新获取一次计算属性值 image.png

这里通过dirty判断要不要重新获取 image.png

image.png