watchEffect

执行传入的一个函数,同时自动追踪函数中依赖到的数据,并在其依赖变更时重新运行该函数。
并且会在 组件挂载前 立即调用一次,(默认是挂载前,可通过修改 flush 属性改变,后边会讲到)
例子
  1. const person = reactive({
  2. count: 0,
  3. });
  4. onBeforeMount(() => {
  5. console.log("onBeforeMount");
  6. });
  7. onMounted(() => {
  8. console.log("onMounted");
  9. });
  10. watchEffect(
  11. () => {
  12.  
  13. const el = document.querySelector(".h1");
  14. console.log(el);
  15. console.log(person.count);
  16. }
  17. );

停止监听器
调用返回值会停止监听,组件卸载时也会自动停止监听 (异步创建的监听器,组件卸载是不会自动停止监听的,需要手动调用,防止内存泄漏)
例子:
  1. const stop = watchEffect(
  2. () => {
  3. console.log(person.count);
  4. }
  5. );
  6. stop ()

    // 注意!异步创建,组件卸载不会停止监听
  1. setTimeout(() => {
  2. watchEffect(() => {})
  3. }, 100)
  1.  
清除副作用
有时副作用函数会执行一些异步的副作用,需要在失效时清除(完成前状态已改变)。
可用调用 onInvalidate 函数。
副作用函数接收一个 onInvalidate 函数作为参数。 onInvalidate 接收一个回调函数。
第一次自调用 effect 副作用函数 是不会触发 onInvalidate 函数的,
触发 onInvalidate 函数有以下情况
依赖数据改变,再次调用 effect 副作用函数,
监听器被停止 (组件卸载前也会调用,因为组件卸载就会停止监听器)
例子
  1. watchEffect(
  2. (onInvalidate) => {
  3. onInvalidate(() => {
  4. console.log("before");
  5. });
  6. const el = document.querySelector(".h1");
  7. console.log(el);
  8. console.log(person.count);
  9. }
  10. );

第一次运行是不会触发

改变数据依赖时触发

组件卸载前触发

 副作用刷新时机

vue 默认会缓存副作用函数,异步刷新,多个依赖数据同时改变也只会触发一次。并且会监听组件更新函数,在组件更新前去触发副作用函数。

可给 watchEffect 传递第二个参数,options 配置对象,改变 副作用函数触发时机,和执行次数。

options 配置对象中,flush 属性有三个值,'pre'、'post' 或 'sync'

pre :默认配置,组件挂载前 和 组件更新前 执行副作用函数,并且会缓存副作用函数,异步刷新,同时改变多个依赖数据只会调用一次副作用函数。

post : 组件挂载后 和 组件更新后 执行副作用函数,并且会缓存副作用函数,异步刷新,同时改变多个依赖数据只会调用一次副作用函数。

sync: 组件挂载前 和 组件更新前 执行副作用函数,不会缓存副作用函数,同步刷新,同时改变多个依赖数据会多次调用副作用函数。少用sync

默认配置,例子:

  1. const state = ref(0);
  2. const person = reactive({
  3. count: 0,
  4. });
  5. const change2 = () => {
  6. state.value++;
  7. person.count++;
  8. };
  9. watchEffect(
  10. (onvalidate) => {
  11. onvalidate(() => {
  12. console.log("before");
  13. });
  14. const el = document.querySelector(".h1");
  15. console.log(el);
  16. console.log(person.count);
  17. console.log(state.value);
  18. }
  19. );

默认情况下 副作用函数会在 组件挂载前 和 组件更新前 执行,并且会缓存副作用函数,异步刷新,同时改变多个依赖数据只会调用一次副作用函数

flush 属性值为 post,例子:

  1. watchEffect(
  2. (onvalidate) => {
  3. onvalidate(() => {
  4. console.log("before");
  5. });
  6. const el = document.querySelector(".h1");
  7. console.log(el);
  8. console.log(person.count);
  9. console.log(state.value);
  10. },
  11. {
  12. flush: "post"
  13. }
  14. );

在 组件挂载后,和 组件更新后 执行,并且会缓存副作用函数,异步刷新,同时改变多个依赖数据只会调用一次副作用函数

flush 属性值为 sync,例子:

  1. watchEffect(
  2. (onvalidate) => {
  3. onvalidate(() => {
  4. console.log("before");
  5. });
  6. const el = document.querySelector(".h1");
  7. console.log(el);
  8. console.log(person.count);
  9. console.log(state.value);
  10. },
  11. {
  12. flush: "sync"
  13. }
  14. );

在 组件挂载前,和 组件更新前 执行,不会缓存副作用函数,同步刷新,同时改变多个依赖数据就多次调用副作用函数

监听器调试

监听器配置对象中,onTrack 和 onTrigger  选项可用于调试监听器行为(开发模式)

onTrack:会在响应式数据被追踪的时候被调用。(就是数据被获取时)

onTrigger: 响应式依赖改变时被调用

例子

  1. const state = ref(0);
  2. const person = reactive({
  3. count: 0,
  4. });
  5. const change2 = () => {
  6. state.value++;
  7. person.count++;
  8. };
  9. watchEffect(
  10. (onvalidate) => {
  11. onvalidate(() => {
  12. console.log("before");
  13. });
  14. const el = document.querySelector(".h1");
  15. console.log(el);
  16. console.log(state.value);
  17. console.log(person.count);
  18. },
  19. {
  20. onTrack(e) {
  21. console.log(e, "track");
  22. },
  23. onTrigger(e) {
  24. console.log(e, "trigger");
  25. },
  26. }
  27. );

第一次自动执行,获取响应式数据依赖,触发 onTrack

改变依赖数据,触发 onTrigger

watch

监听特定的数据源,在回调函数中执行副作用,默认只有数据改变才会执行副作用函数, 不会立即调用副作用函数(可配置)

和 watchEffect 相比

  • 能访问监听数据变化前后值
  • 手动添加声明监听哪些数据
  • 也有 onInvalidate, 会作为回调函数的第三个参数,(注意,副作用函数第二次执行才会调用 onInvalidate)
  • 配置选项 flush 等.. watch 都有,多了 deep选项和 immediate 选项

监听单个数据源,例子

  1. const state = ref(0);
  2. const person = reactive({
  3. count: 0,
  4. });
  5. const change2 = () => {
  6. state.value++;
  7. person.count++;
  8. };
  9. // 侦听一个 getter
  10. watch(
  11. () => person.count,
  12. (count, prevCount) => {
  13. console.log(count, "count");
  14. console.log(prevCount, "prevCount");
  15. }
  16. );
  17.  
  18. // 直接侦听ref
  19. watch(state, (state, prevState) => {
  20. console.log(state, "count");
  21. console.log(prevState, "prevCount");
  22. });

监听多个数据源,并且配置选项,例子

  1. const state = ref(0);
  2. const person = reactive({
  3. count: 0,
  4. });
  5. const change2 = () => {
  6. state.value++;
  7. person.count++;
  8. };
  9. watch(
  10. [() => person.count, state],
  11. (arr, prevArr, onvalidate) => {
  12. console.log(arr, "arr");
  13. console.log(prevArr, "prevArr");
  14. onvalidate(() => {
  15. console.log("before");
  16. });
  17. },
  18. {
  19. immediate: true,
  20. flush: "pre",
  21. onTrigger(e) {
  22. console.log(e, "trigger");
  23. },
  24. onTrack(e) {
  25. console.log(e, "track");
  26. },
  27. }
  28. );

监听多个数据源用数组写法,回调函数参数1和2 也变成数组,配置选项 immediate 为 ture 时,初始化时会自执行一次副作用函数, 其它的配置项和 watchEffect 没区别

监听对象或数组,什么情况下配置 deep 选项

数据类型 直接监听 getter 写法 克隆数据,必须采用 getter 写法
ref 需要deep 需要deep 不需要deep
reactive 不需要deep 需要deep 不需要deep

(注意,响应式数据为对象时直接监听,用的是同一个对象的引用,导致回调函数参数1和2,改变前后数据相同)。所以要克隆一个副本监听此副本,并使用 getter 写法。

例子:

  1. const person = ref({
  2. name: { Anna: { count: 0 } },
  3. });
  4. const person2 = reactive({
  5. name: { Anna: { count: 0 } },
  6. });
  7. const change2 = () => {
  8. person.value.name.Anna.count++;
  9. person2.name.Anna.count++;
  10. };
  11. // 直接监听 ref
  12. watch(
  13. person,
  14. (person, prevPerson) => {
  15. console.log(person.name.Anna, "person");
  16. console.log(prevPerson.name.Anna, "prevPerson");
  17. },
  18. {
  19. deep: true,
  20. }
  21. );
  22. // 直接监听 reactive
  23. watch(person2, (person, prevPerson) => {
  24. console.log(person.name.Anna, "person");
  25. console.log(prevPerson.name.Anna, "prevPerson");
  26. });
  27. // 监听reactive,getter 写法
  28. watch(
  29. () => person2,
  30. (person, prevPerson) => {
  31. console.log(person.name.Anna, "person");
  32. console.log(prevPerson.name.Anna, "prevPerson");
  33. },
  34. {
  35. deep: true,
  36. }
  37. );

回调函数参数 1和2 出现数据相同 的问题

克隆响应式数据再监听,需要 getter 写法

  1. const person = reactive({
  2. name: { Anna: { count: 0 } },
  3. });
  4. const change2 = () => {
  5. person.name.Anna.count++;
  6. };
  7. watch(
  8. () => deepClone(person),
  9. (person, prevPerson) => {
  10. console.log(person.name.Anna, "person");
  11. console.log(prevPerson.name.Anna, "prevPerson");
  12. }
  13. );

现在 回调函数参数1和2,改变前后数据就正确了

建议:响应式数据为对象或数组用watch监听时,用 getter 写法。

vue3 watch笔记的更多相关文章

  1. vue3 学习笔记 (二)——axios 的使用有变化吗?

    本篇文章主要目的就是想告诉我身边,正在学 vue3 或者 准备学 vue3 的同学,vue3中网络请求axios该如何使用,防止接触了一点点 vue3 的同学会有个疑问?生命周期.router .vu ...

  2. vue3 学习笔记 (四)——vue3 setup() 高级用法

    本篇文章干货较多,建议收藏! 从 vue2 升级到 vue3,vue3 是可以兼容 vue2 的,所以 vue3 可以采用 vue2 的选项式API.由于选项式API一个变量存在于多处,如果出现问题时 ...

  3. vue3 学习笔记(九)——script setup 语法糖用了才知道有多爽

    刚开始使用 script setup 语法糖的时候,编辑器会提示这是一个实验属性,要使用的话,需要固定 vue 版本. 在 6 月底,该提案被正式定稿,在 v3.1.3 的版本上,继续使用但仍会有实验 ...

  4. vue3 学习笔记 (五)——vue3 的 setup 如何实现响应式功能?

    setup 是用来写组合式 api ,内部的数据和方法需要通过 return 之后,模板才能使用.在之前 vue2 中,data 返回的数据,可以直接进行双向绑定使用,如果我们把 setup 中数据类 ...

  5. vue3 高阶 API 大汇总,强到离谱

    高阶函数是什么呢? 高阶函数英文名叫:Higher Order function ,一个函数可以接收一个或多个函数作为输入,或者输出一个函数,至少满足上述条件之一的函数,叫做高阶函数. 前言 本篇内容 ...

  6. Vue3 全家桶,从 0 到 1 实战项目,新手有福了

    前端发展百花放,一技未熟百技出.未知何处去下手,关注小编胜百书. 我是前端人,专注分享前端内容! 本篇文章主要是,使用 vite 创建一个vue3 项目,实践 vie-router4 vuex4 结合 ...

  7. 尤雨溪在直播中讲到的Vue3.0 Beta的那些特性,快记笔记了

    前言 在那天风雨交加的夜晚,Vue的创作者尤雨溪尤大大在b站直播分享了Vue.js 3.0 Beta最新进展.我对直播的内容进行了一下整理.整整用了三天的空余时间赶上了 1. 全新文档RFCs Vue ...

  8. vue 3 学习笔记 (七)——vue3 中 computed 新用法

    vue3 中 的 computed 的使用,由于 vue3 兼容 vue2 的选项式API,所以可以直接使用 vue2的写法,这篇文章主要介绍 vue3 中 computed 的新用法,对比 vue2 ...

  9. Vue3.x+element-plus+ts踩坑笔记

    闲聊 前段时间小颖在B站找了个学习vue3+TS的视频,自己尝试着搭建了一些基础代码,在实现功能的过程中遇到了一些问题,为了防止自己遗忘,写个随笔记录一下嘻嘻 项目代码 git地址:vue3.x-ts ...

  10. vue3.0学习笔记(二)

    一.选择合适的ide 推荐使用vs code编辑器,界面清晰.使用方便,控制台功能很好用.webstorm也可以,看个人喜好. 二.ui框架选择 目前,pc端一般是选择element ui(饿了么), ...

随机推荐

  1. 重要参考文档---MySQL 8.0.29 使用yum方式安装,开启navicat远程连接,搭建主从,读写分离(需要使用到ProxySQL,此文不讲述这个)

    yum方式安装 echo "删除系统默认或之前可能安装的其他版本的 mysql" for i in $(rpm -qa|grep mysql);do rpm -e $i --nod ...

  2. 使用Metricbeat监控zookeeper遇到的问题

    1.metricbeat中启动自动加载模块 metricbeat.config.modules: path: ${path.config}/modules.d/*.yml reload.enabled ...

  3. Kubernetes的kubectl常用命令速记

    文章转载自:https://mp.weixin.qq.com/s/0kqQzeA-MzCOhPMkmiR4_A kubectl是用来管理Kubernetes集群的命令行工具. kubectl默认在&q ...

  4. 使用pip的方式安装docker-compose

    # 国内开启pip 下载加速:http://mirrors.aliyun.com/help/pypi mkdir ~/.pip/ cat > ~/.pip/pip.conf <<'E ...

  5. GCC Arm 12.2编译提示 LOAD segment with RWX permissions 警告

    使用GCC Arm工具链开发的项目, 在升级到 arm-gnu-toolchain-12.2 之后, 编译出现警告 arm-gnu-toolchain-12.2.mpacbti-bet1-x86_64 ...

  6. 二叉树及其三种遍历方式的实现(基于Java)

    二叉树概念: 二叉树是每个节点的度均不超过2的有序树,因此二叉树中每个节点的孩子只能是0,1或者2个,并且每个孩子都有左右之分. 位于左边的孩子称为左孩子,位于右边的孩子成为右孩子:以左孩子为根节点的 ...

  7. ZJOI2007报表统计

    题目链接 比较简单的一道平衡树题. 第三个操作可以直接用map完成(加进去一个数只会让答案变小,于是与它的前面后面一个数做差更新答案即可),只考虑前两个操作. ·维护区间内的最大最小值,以及区间相邻两 ...

  8. 你的哪些骚操作会导致Segmentation Fault😂

    你的哪些骚操作会导致Segmentation Fault 前言 如果你是一个写过一些C程序的同学,那么很大可能你会遇到魔幻的segmentation fault,可能一时间抓耳挠腮,本篇文章主要介绍一 ...

  9. java:找不到符号

    出现这种情况的原因之一:实体类的字段修改过.实体类中的变量名修改.然而其他地方调用的字段名还是修改之前的变量.

  10. Dubbo 原理和机制详解 (非常全面)

    Dubbo 是一款Java RPC框架,致力于提供高性能的 RPC 远程服务调用方案.作为主流的微服务框架之一,Dubbo 为开发人员带来了非常多的便利. 大家好,我是 mikechen,专注分享「互 ...