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

vue3源码学习(四)watch 源码学习

vue3源码学习(四) —— watch 源码学习

watch 源码学习回顾、复习。


watch 源码学习

  • vue3源码学习(四) —— watch 源码学习
  • 一、实现 watch 基础函数
      • 1、汇总概念
      • 2、实现 watch 函数
      • 3、实现watch的immediat、deep 选项
  • 二、完整代码


vue3.x使用示例:

import { reactive, effect, computed, watch } from './reactivity.esm.js';
const state = reactive({name: 'zhangsan',age: 32
})// 数据变化后调用回调函数
// 常见两种方式  直接监控某个对象  或者 监控某个具体的值// 常见写法一: 监听对象
// 直接监听对象, 不建议 深度监听
watch(state, (newVal, oldVal) => {console.log('监听到数据变化了');
})// 常见写法二: 监听具体的值
watch(() => state.name,(newVal, oldVal) => {console.log('name变化了', newVal, oldVal);
})

watch使用方法多种多样在此不做赘述,如需了解点击链接学习 watch其他写法

一、实现 watch 基础函数

1、汇总概念

  • 数据变化后调用回调函数
  • 常见两种方式 直接监控某个对象 或者 监控某个具体的值
  • watch 就是effect, 状态会收集watch effect, 属性变化后会触发scheduler
  • 默认的effect会在组件中用 -> 渲染effect 计算属性effect 用户effect(watch) 三种effect
  • 组件渲染effect 和 计算属性effect 是同步执行的, 用户effect(watch) 是异步执行的

2、实现 watch 函数

分析:参数1:函数或者对象, 参数二:回调函数

export function isReactive(target) {// 如果访问的是__v_isReactive属性,返回truereturn !!(target && target[ReactiveFlags.IS_REACTIVE])
}// 递归收集依赖
// 通过递归来访问对象的每一个key从而实现收集依赖
function traverse (source, set=new Set()){if(isObject(source)){if(set.has(source)){return source}else{for(let key in source){// 考虑循环引用的问题, 采用set来存储已经访问过的对象traverse(source[key])}}}return source
}// 这里只对immediate,deep这两个参数做处理
export function watch(source, cb){let oldValue; //记录旧值// 首先判断source类型且是不是响应式类型let getter;if(isReactive(source)){getter = () => traverse(source) 			}else if(isFunction){getter = source;}const job = () => {let newValue = effect.run()cb(newValue, oldValue)oldValue = newValue}// watch本身也就是一个effectlet effect = new ReactiveEffect(getter, job)oldValue = effect.run() // 默认执行一次记录老值老值
}

3、实现watch的immediat、deep 选项

export function watch (source, cb, { immediate = false, deep = false } = {}) {let oldValue;let getter;if(isReactive(source)){// 最终都处理成函数getter = () => traverse(source); // 稍后直接调用run的时候会执行此函数,直接返回对象,只访问属性才能收集依赖}else if(isFunction(source)){if(deep){getter = () => traverse(source());}else{getter = source;}}const job = () => {// 内部要调用cb也就是watch的回调方法let newValue = effect.run();cb(newValue, oldValue);oldValue = newValue;}let effect = new ReactiveEffect(getter, job)// immediate为true时, 立即执行回调if(immediate){return job();}oldValue = effect.run(); // 默认执行一次保留老值
}

二、完整代码

import { isFunction, isObject } from "@vue/shared";
import { ReactiveEffect } from "./effect";
import { isReactive } from "./reactive";// 递归收集依赖
const traverse = (source, set=new Set()) => {if(isObject(source)){if(set.has(source)){return source;}else{// 考虑循环引用的问题, 采用set来存储已经访问过的对象set.add(source);for(const key in source){traverse(source[key], set)}}}return source;
}export function watch (source, cb, { immediate = false, deep = false } = {}) {let oldValue;let getter;if(isReactive(source)){// 最终都处理成函数getter = () => traverse(source); // 稍后直接调用run的时候会执行此函数,直接返回对象,只访问属性才能收集依赖}else if(isFunction(source)){if(deep){getter = () => traverse(source());}else{getter = source;}}const job = () => {// 内部要调用cb也就是watch的回调方法let newValue = effect.run();cb(newValue, oldValue);oldValue = newValue;}let effect = new ReactiveEffect(getter, job)// immediate为true时, 立即执行回调if(immediate){return job();}oldValue = effect.run(); // 默认执行一次保留老值
}

文章转载自:

http://BLvJ3bKI.tLdfp.cn
http://hVfyGLhy.tLdfp.cn
http://uVbki28a.tLdfp.cn
http://1bxpYFsz.tLdfp.cn
http://9zl1ITVp.tLdfp.cn
http://gREIeNRp.tLdfp.cn
http://rzjlKuvi.tLdfp.cn
http://iVN9Kbav.tLdfp.cn
http://4KHlYx0w.tLdfp.cn
http://MRDKAKgQ.tLdfp.cn
http://9JYCvxQu.tLdfp.cn
http://eeUEr9Iu.tLdfp.cn
http://TsXvjZ8Y.tLdfp.cn
http://7euA3Hn9.tLdfp.cn
http://JLWqrFAF.tLdfp.cn
http://90mP1PXL.tLdfp.cn
http://RwZgfLo2.tLdfp.cn
http://mn4vDuA4.tLdfp.cn
http://IvHgIfQx.tLdfp.cn
http://qRSWKBPg.tLdfp.cn
http://jC0RGJUG.tLdfp.cn
http://AunCxsRH.tLdfp.cn
http://NYnsj1tg.tLdfp.cn
http://WUU0qek0.tLdfp.cn
http://3rGjKazJ.tLdfp.cn
http://CwPckWLs.tLdfp.cn
http://2iJt08x6.tLdfp.cn
http://CNdmb00h.tLdfp.cn
http://8ztKE6rE.tLdfp.cn
http://pay1ufyB.tLdfp.cn
http://www.dtcms.com/a/378253.html

相关文章:

  • 利用JSONCrack与cpolar提升数据可视化及跨团队协作效率
  • 短剧小程序系统开发:打造个性化娱乐新平台
  • 从MySQL到StarRocks:全量与增量同步的最佳实践
  • 第七篇:识破“共因失效”——如何阻止汽车系统的“团灭”危机
  • SSL部署完成,https显示连接不安全如何处理?
  • Java 与 AI 生态:深度学习框架的支持现状
  • Linux iptables 实战:配置 NAT 端口转发访问内网 MySQL
  • docker,自定义镜像dockerfile
  • 分布式专题——9 Redis7底层数据结构解析
  • WPF 数据绑定模式详解(TwoWay、OneWay、OneTime、OneWayToSource、Default)
  • 前端埋点系统架构设计与优化实践
  • SEO新手入门:什么是SEO及其作用
  • Nginx性能优化与防盗链实战指南
  • C++类(上)默认构造和运算符重载
  • 字符串大数相加:从初稿到优化的思路演进
  • 追根索源-神经网络的灾难性遗忘原因
  • 零碎的嵌入式笔记2
  • 室内配线工程量计算-批量测量更方便
  • 深入理解 Gateway 网关:原理、源码解析与最佳实践
  • 3.List,set 与 Zset(Redis数据类型)
  • 前沿探索:RISC-V 架构 MCU 在航天级辐射环境下的可靠性测试
  • 苹果上架App软件全流程指南:iOS 应用发布步骤、App Store 上架流程、uni-app 打包上传与审核技巧详解
  • NW622NW623美光固态闪存NW624NW635
  • 38.自编码器:AI的压缩与重建艺术
  • leetcode-python-2418按身高排序
  • 【学习日记】
  • 【Android View】事件分发机制
  • 深入了解linux系统—— 线程池
  • 视频理解新纪元!VideoChat双模架构突破视频对话瓶颈,开启多模态交互智能时代
  • 【115】基于51单片机GSM防火防盗报警系统【Proteus仿真+Keil程序+报告+原理图】