当前位置: 首页 > news >正文

手写 vue 源码 === watch 实现

目录

1. watch 的基本使用

2. watch 的整体架构

3. doWatch 函数的实现

3.1 处理不同类型的监听源

3.2 清理副作用的机制

3.3 创建响应式效果

3.4 初始化执行

3.5 返回停止函数

4. watch 如何基于 ReactiveEffect 实现

4.1 依赖收集过程详解

4.2 更新触发过程详解

5. 深度遍历的实现细节

6. 实际执行流程示例

6.1 初始化阶段

6.2 更新阶段

7. watch 与 computed 的对比

8. 高级应用:清理副作用

总结


Vue 的响应式系统是其核心特性之一,而 watch  作为响应式系统的重要组成部分,允许我们监听数据变化并执行相应的回调函数。本文将深入探讨 Vue 中 watch  的实现原理,从源码角度逐步分析其工作机制。

1. watch 的基本使用

在深入实现原理之前,让我们先回顾一下 watch 的基本用法:

// 监听响应式对象
watch(state, (newVal, oldVal) => {console.log(newVal, oldVal);
});// 监听 ref 对象
watch(name, (newVal, oldVal) => {console.log(newVal, oldVal);
});// 监听 getter 函数
watch(() => state.name, (newVal, oldVal) => {console.log(newVal, oldVal);
}, {deep: true,      // 是否深度监听immediate: true  // 是否立即执行
});

2. watch 的整体架构

从源码中可以看出, watch 函数本质上是对 doWatch  函数的封装:

export function watch(source, cb, options = {} as any) {// watchEffect 也是基于这个实现return doWatch(source, cb, options);
}

而 watchEffect 也是基于同一个 doWatch  函数实现的,只是没有回调函数:

export function watchEffect(fn, options = {} as any) {return doWatch(fn, null, options);
}

3. doWatch 函数的实现

doWatch 函数是 watch  和 watchEffect  的核心实现,它处理不同类型的监听源,并设置相应的依赖收集和触发机制。

3.1 处理不同类型的监听源

doWatch 首先需要处理不同类型的监听源,将其转换为统一的 getter 函数:

function doWatch(source, cb, { deep, immediate }) {// source > getterconst ReactiveGetter = (source) =>traverse(source, deep === false ? 1 : undefined);let getter;let oldValue;let cleanup;// 处理不同类型的监听源if (isReactive(source)) {getter = () => ReactiveGetter(source);} else if (isRef(source)) {getter = () => source.value;} else if (isFunction(source)) {getter = source;}// ...
}

这里根据监听源的类型设置不同的 getter 函数:

  • 对于响应式对象,使用   ReactiveGetter  函数遍历对象
  • 对于 ref 对象,直接获取其 value 属性
  • 对于函数,直接使用该函数作为 getter

3.2 清理副作用的机制

watch 提供了清理副作用的机制,通过 onCleanup  函数注册清理函数:

const onCleanup = (fn) => {cleanup = () => {fn();cleanup = null;};
};

这个机制允许我们在下一次回调执行前清理上一次回调产生的副作用,比如取消异步请求等。

3.3 创建响应式效果

 doWatch 的核心是创建一个 ReactiveEffect  实例,它负责依赖收集和触发更新:

const job = () => {if (cb) {const newValue = effect.run();if (cleanup) {cleanup(); // 在执行回调之前,先执行清理}// 执行cbcb(newValue, oldValue, onCleanup);oldValue = newValu
http://www.xdnf.cn/news/414883.html

相关文章:

  • 学习黑客5分钟深入浅出理解系列之Windows compmgmt
  • 配置Hadoop集群-免密登录
  • dfs第二次加训 详细题解 下
  • STM32G474VET6-CAN FD使用经典模式+过滤报文ID
  • ESOP系统如何帮助玩具工厂实现生产数据实时展示
  • rufus+Ubuntu 18.04 镜像
  • Promise/A+ 规范中文解读
  • Matlab基于PSO-MVMD粒子群算法优化多元变分模态分解
  • 【C语言指针超详解(五)】--回调函数,qsort函数的理解和使用,qsort函数的模拟实现
  • 类神经网络训练失败怎么办?
  • 中央处理器(CPU)(概述、指令周期)
  • 阿里云服务器核心用途解析:从基础应用到行业创新​
  • c++刷题便捷函数(类似于stoi的小函数)
  • 超越合并速度(merge speed):AI如何重塑开发者协作
  • Hadoop集群的常用命令
  • axi uart 16550 ip core使用流程
  • 一、HAL库的设计理念详解:从架构到实践
  • 274、H指数
  • StringBuilder,StringJoiner,StringBuffer字符串处理类深度解析
  • 从零到精通:GoFrame 的 garray 模块深度解析与实战经验分享
  • Nacos源码—8.Nacos升级gRPC分析五
  • 【K8S学习之生命周期钩子】详细了解 postStart 和 preStop 生命周期钩子
  • 【日撸 Java 三百行】Day 13(链表)
  • 【AIGC梦幻婚纱美学】:白纱与花卉的浪漫算法融合
  • 2025-5-12 底部埋伏记录
  • Matlab 基于GUI的图像去雾技术GlobalHisteq、LocalHisteq和Retinex
  • 基于世界土壤数据库(HWSD)的中国土壤数据集(v1.1)(2009)
  • 大核极坐标码
  • vulhub-Stapler
  • 耀圣-高温釜进料口气动耐磨切断球阀:高粘度、高腐蚀颗粒介质的终极进料解决方案