Vue响应式原理

Vue响应式原理

  • 数据劫持:vue2的Object.defineProperty(对属性添加getter和setter方法),vue3的Proxy。
  • 依赖收集:模板渲染时收集,computed收集,watch收集。
  • 依赖执行:将收集到的依赖依次执行。
    依赖其实就是数据变化时要执行的函数。

依赖收集

Vue 响应式依赖收集的核心是收集数据变化时需要重新执行的代码,具体包括:

  • 组件模板渲染的「更新函数」(最核心);
  • 计算属性的「求值函数」;
  • watch/watcher 的用户自定义的「回调函数」;
  • 手动通过 watchEffect/ReactiveEffect 等 API 定义的「自定义函数」。

依赖收集的本质是「响应式数据与执行函数的映射」,数据变化时通过映射关系精准触发函数执行,这也是 Vue 实现「数据驱动视图」的核心原理。

源码解析

vue2是通过Dep类收集(watcher),Dep类维护一个watcher数组,数据变化时通知watcher更新。

vue3是通过effect函数收集。get时调用track收集依赖,set时调用trigger触发所有的effect更新。

vue2通过watcher类收集依赖

  • 渲染watcher
    每个组件在挂载时都会创建一个渲染watcher,负责渲染视图时的依赖收集。
js 复制代码
new Watcher(vm, updateComponent, noop, watcherOptions,true)    /* isRenderWatcher */
  • 计算属性(缓存)

    每一个计算属性内部维护一个dirty属性,表示是否需要重新计算。

    当取值时dirty为true就会执行计算函数计算值,拿到值缓存起来this.value, 并将dirty设置为false。

    再次取值时,dirty为false就直接返回缓存的值this.value。

    当计算属性依赖的数据变化时,会将dirty设置为true,下次访问计算属性时会重新计算值。

  • 计算属性watcher(lazy:true)

js 复制代码
new Watcher(vm, getter, noop, {lazy: true})

计算属性会创建一个计算属性watcher,lazy:true表示懒执行。不会立即执行计算函数。

通过Object.defineProperty给计算属性添加getter和setter方法。

当访问计算属性时会调用getter方法,拿到计算属性watcher,看看dirty属性是否为true,如果是true就执行计算函数计算值,并将dirty设置为false。

同时让计算属性watcher中依赖的属性收集最外层的渲染watcher,这样当计算属性依赖的数据变化时会通知渲染watcher更新视图。

  • 用户watch定义时的watcher
js 复制代码
new Watcher(vm, expOrFn, cb, options)   //cb是用户定义的回调函数。

用户通过watch选项或者$watch方法创建的watcher。

vue3通过effect函数收集依赖

  • 渲染effect:
js 复制代码
const effect = (instance.effect = new ReactiveEffect(
                                        componentUpdateFn) )
  • 计算属性effect
js 复制代码
const effect = new ReactiveEffect(getter, () => {
                if (!dirty) {
                    dirty = true
                    // 计算属性依赖的属性变化时,通知计算属性收集的渲染effect更新
                    triggerRefValue(computedRefImpl)
                }
            })

和vue2不一样的是,这个计算属性会收集当前组件渲染的effect作为它的依赖。不需要普通属性自己去收集渲染watcher。

计算属性依赖的属性变化时,会通知计算属性effect更新dirty, 并且计算属性会触发自己收集的渲染effect执行。

  • 用户watch effect
js 复制代码
const effect = new ReactiveEffect(getter, () => {
                // 当数据变化时执行回调
                job()
            })
相关推荐
YIAN9 小时前
从 SSE 流式到结构化输出:LangChain 三大 OutputParser 与 ToolCall 方案全实战
前端·langchain·node.js
FYKJ_20109 小时前
springboot雅集社区养老管理系统04456-计算机课程设计、毕业设计
vue.js·spring boot·python·mysql·typescript·spark·django
FYKJ_20109 小时前
express皖美特色农产品网售系统53118-计算机课程设计、毕业设计
javascript·vue.js·spring boot·mysql·typescript·spark·express
YIAN9 小时前
从 SSE 流式原理到 LangChain 结构化输出:打字机效果与 JSON 解析全方案实战
前端·langchain
Moment9 小时前
如果你在做 RAG,可能会需要 pdf-inspector
前端·后端·面试
gnip9 小时前
Flutter 原生插件开发实战指南
前端·flutter
FYKJ_20109 小时前
springboot羽毛球场地管理系统00626-计算机课程设计、毕业设计
vue.js·spring boot·python·mysql·typescript·spark·django
晓得迷路了10 小时前
栗子前端技术周刊第 148 期 - Turborepo 2.11、Chrome 154 iframe、Node.js 26...
前端·javascript·css
IT_陈寒10 小时前
Vite热更新失效?你可能漏了这个配置项
前端·人工智能·后端
FYKJ_201010 小时前
django药饮个性化推荐系统54839-计算机课程设计、毕业设计
vue.js·spring boot·python·mysql·typescript·spark·django