第七节:带你全面理解vue3: 其他响应式进阶API

前言:

针对vue3官网中, 响应式:进阶API 中, 我们在上一章中给大家讲解了shallowRef, shallowReactive, shallowReadonly几个API的使用.

本章主要对剩下的API 进行讲解, 我们先看一下官网中进阶API 都有那些

img

对于剩下这些API, 你需要了解他们创建目的, 是为了解决之前的API存在的那些痛点问题, 这样你就能更好的了解使用他们的细节.工作中就可以有的放矢的选择不同的API.

1. triggerRef

我们首先来分析一下triggerRefAPI 的使用

1.1. triggerRef 针对的痛点问题

我们先看一个痛点问题:

对于ref响应式数据的变化, vue帮我们处理副作用. 比如,页面的更新, watchEffect侦听器回调函数的调用等.

但对于浅层响应数据, 比如shallowRef创建的数据, 其深层并不具有响应性, 也就是说vue并没有监测这些数据的变化, 当对深层数据进行修改时, 并不会触发副作用, 比如页面不会自动刷新.

triggerRefAPI 就是为了解决shallowRef浅层响应式数据深层修改问题.

当深层修改时, 会强制触发依赖于一个浅层 ref 的副作用,这通常在对浅引用的内部值进行深度变更后使用。

1.2. triggerRef 类型

类型:

function triggerRef(ref: ShallowRef): void

triggerRefAPI 函数接收一个shallowRefAPI 创建的数据, 作用就是强制触发这个浅层ref数据的副作用.

1.3. triggerRef 使用示例

示例:

<template>
  <div>
    <h3>shallowReadonly</h3>
    <div>{{ count }}</div>
    <div>{{ count2 }}</div>
    <button @click="change">修改数据源</button>
  </div>
</template>

<script lang="ts">
import { defineComponent, readonly, ref, shallowReadonly, shallowRef, triggerRef, watchEffect } from 'vue'

export default defineComponent({
  setup() {
    const count = ref({ num: 0 })
    const count2 = shallowRef({ num: 0 })


    // 对于ref 数据, 是深层响应式,
    // 因此当我们通过count.value.num++ 修改数据时,依然会触发watchEffect副作用函数
    watchEffect(() => {
      console.log('count.value.num', count.value.num)
    })


    // 因为shallowRef 数据不是深层响应式, 只有.value 整体修改才会触发响应式
    // 因为当我们通过count2.value.num++ 修改数据时,不会出发watchEffect 副作用函数
    // 同时视图也不会发生更改
    watchEffect(() => {
      console.log('count2.value.num', count2.value.num)
    })


    // 修改数据
    const change = () => {
      // count.value.num++
      count2.value.num++

      // 如果希望shallowRef 深层数据修改后,触发视图更新
      // 那么就需要使用triggerRef 手动触发更新
      triggerRef(count2)  // 手动更新count2
    }
    return { count, count2, change }
  }
})
</script>

通过示例的运行结果, 你也可以看出. shallowRef创建响应式数据, 在深层数据发生变化时, 不会触发页面更新 和watchEffect的处理函数. 因为深层不具有响应性.

当我们手动调用triggerRef函数, 并将shallowRef创建数据作为参数, 就是告诉vue , 我们需要强制执行shallowRef数据的副作用. 此时页面将会更新, watchEffect处理函数也会自动执行

1.4. triggerRef 使用小结

在理解triggerRefAPI 的使用后, 针对该API, 我做了以下小结

  • triggerRef常与shallowRef搭配使用
  • triggerRef会强制更新以shallowRef数据作为依赖的副作用,ref数据会自动触发这些副作用

我们需要注意的是: vue3只提供了triggerRef这个方法,但没有提供triggerReactive的方法。 也就是说triggerRef 【不可以】去更改 shallowReactive创建的数据

2. toRaw

根据一个 Vue 创建的代理返回其原始对象

2.1. toRaw 针对的问题

vue3中, 我们通过 reactive()readonly()shallowReactive() shallowReadonly()四个API 创建的响应式数据, 本质上就是通过Proxy创建的代理对象.

但有时我们在做数据传输时, 我们并不需要传响应式数据, 我们只想传最基本的原始对象.

toRawAPI 的作用就是返回 reactive()readonly()shallowReactive(),shallowReadonly() 创建的代理对应的原始对象。

2.2. toRaw 类型

toRaw 函数签名

function toRaw<T>(proxy: T): T

toRawAPI 函数接收一个Proxy代理对象(响应式对象)作为参数,

2.3. toRaw 使用示例

示例:

<template>
  <div>
    <h3>shallowReactive</h3>
    <div>{{ user }}</div>
    <button @click="change">修改数据源</button>
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive, toRaw } from 'vue'

export default defineComponent({
  setup() {
    // 代理目标对象
    const obj = { name: '张三', age: 18 }

    // reactive 处理的代理对象
    const user = reactive(obj)

    // 控制触发代理对象
    console.log('user', user)

    // 使用toRaw, 参数是代理对象, 返回代理对象的目标对象
    console.log('toRaw(user)', toRaw(user))
    console.log('toRaw(user) === obj', toRaw(user) === obj)  // true

    // 修改数据
    const change = () => {
      user.name = '李四'

    }
    return { user, change }
  }
})
</script>

通过控制台输出结果, 你可以看出, toRaw 就是获取代理对象的原目标对象.

这是一个可以用于临时读取而不引起代理访问/跟踪开销,或是写入而不触发更改的特殊方法。不建议保存对原始对象的持久引用,请谨慎使用。

这句话来自于官网, 这句话你可以这么理解,

代理对象具有响应性, 可以理解为vue在监测这个数据的变化, 这个监测会消耗性能. 如果你的操作不要触发副作用, 就没有必要 使用具有响应性的代理对象.

比如调用接口时传入的参数, 就可以使用toRaw去掉代理对象的外壳, 获取到原始对象传入接口.

3. markRaw

markRaw 函数的作用就是将一个对象转为不可代理对象.

如果使用reactiveAPI , 也不会代理markRaw函数返回的对象, 会直接返回原对象.

示例:

<template>
  <div>
    <h3>shallowReactive</h3>
    <div>{{ user }}</div>
    <button @click="change">修改数据源</button>
  </div>
</template>

<script lang="ts">
import { defineComponent, markRaw, reactive } from 'vue'

export default defineComponent({
  setup() {
    // 代理目标对象
    const obj = { name: '张三', age: 18 }

    // 将obj原始对象标记为不可代理
    const markObj = markRaw(obj)

    // reactive 处理的代理对象
    const user = reactive(markObj)

    // user 不是代理对象
    console.log('user', user)


    // 修改数据
    const change = () => {
      user.name = '李四'

    }
    return { user, change }
  }
})
</script>

控制台输出:

img

通过控制台输出结果, 可以看出, 通过markRaw 处理过的对象具有一个__v_skip的属性, 用于标记这个对象不能创建代理对象, 即响应式数据.

尽管你将该对象传入reactive, 返回的也不是一个代理对象, 而是原对象.

既然不是响应数据,修改user.name 时, 就不会触发视图更新

该API的作用就是, 帮助你给一些你不希望创建为代理对象的原始对象添加标记.

4. effectScope

4.1. effectScope 作用

vue3的使用过程中,我们可能会针对同一个响应式数据创建多个副作用.比如computed, watch, watchEffect等.

再次过程中, 如果关闭某个副作用, 比如watch创建的侦听器, 就需要通过返回值关闭. 那么多个副作用你就需要一个一个关闭. 使用相对麻烦

effectScope字面意思就是副作用作用域, 可以理解为, 该函数创建一个作用域, 将所有的副作用放在共同一个作用域中, 如果以后想统一关闭副作用, 就可以使用作用域整体关闭.

4.2. effectScope

类型

function effectScope(detached?: boolean): EffectScope

interface EffectScope {
  run<T>(fn: () => T): T | undefined // 如果作用域不活跃就为 undefined
  stop(): void
}

effectScope函数返回一个作用域对象, 即EffectScope类型.

该作用域对象上具有run, stop方法, 同时run方法接收一个回调函数作为参数.

4.3. effectScope 使用方式

通过effectScope函数创建一个 effect 作用域,可以捕获其中所创建的响应式副作用 (即计算属性和侦听器),这样捕获到的副作用可以一起处理。

示例:

<template>
  <div>
    <h3>shallowReactive</h3>
    <div>{{ count }}</div>
    <button @click="change">修改数据源</button>
  </div>
</template>

<script lang="ts">
import { computed, defineComponent, effectScope, markRaw, reactive, ref, shallowReactive, toRaw, watch, watchEffect } from 'vue'

export default defineComponent({
  setup() {
    // 创建ref 数据
    const count = ref(10)

    // 创建副作用作用域
    const scope = effectScope()
    // 控制台输出 effect 作用域
    console.log("scope", scope);
    
    // 收集运行的副作用
    scope.run(() => {
      // 计算属性副作用
      const computedCount = computed(() => count.value * 2
      )

      // watch 侦听副作用
      watch(
        count,
        () => {
          console.log('computedCount', computedCount.value)
          console.log('watch count', count.value)
        }
      )

      // watchEffect 副作用
      watchEffect(() => {
        console.log('watchEffect count', count.value)
      })

    })


    console.log('scope', scope) 
    // 2秒以后关闭所有的副作用
    setTimeout(() => {
      scope.stop()
    }, 2000)
    
    // 修改数据
    const change = () => {
      count.value++

    }
    return { count, change }
  }
})
</script>

控制台输出结果:

img

通过控制台输出的effect作用域对象, 你可以看到, 作用域将回调函数中的副作用进行了收集, 存储在effects属性上.

同时effect作用域对象原型对象上具有run收集副作用的方法, stop关闭副作用的方法.

5. getCurrentScope

getCurrentScope函数返回当前活跃的 effect 作用域。

在前一个API中, 给大家讲解了effectScope函数, 该函数执行后会返回一个effect 作用域, 通过调用effect作用域对象的run方法收集所有副作用. 我们就可以在run方法的回调函数中, 通过getCurrentScope函数获取到正在活跃的effect作用域对象.

示例:

// 创建副作用作用域
const scope = effectScope();
console.log("scope", scope);

// 收集运行的副作用
scope.run(() => {
  // 计算属性副作用
  const computedCount = computed(() => count.value * 2);

  // watch 侦听副作用
  watch(count, () => {
    console.log("computedCount", computedCount.value);
    console.log("watch count", count.value);
  });

  // watchEffect 副作用
  watchEffect(() => {
    console.log("watchEffect count", count.value);
  });

  // 通过  getCurrentScope() 获取当前真正活跃的 effect 作用域对象
  const effectScope = getCurrentScope();

  console.log("getCurrentScope", effectScope === scope);
  // 控制台输出结果: getCurrentScope true
});

示例中, 我们通过effectScope创建了一个effect作用域对象, 当调用该作用域对象的run方法,传入回调函数, 会自动执行回调函数, 收集副作用, 并将收集到的副作用保存在副作用effect作用域中. 也就是说, 在执行回调函数时, 我们创建的scope就是活跃的effect作用域

之后,我们通过执行getCurrentScope函数获取当前活跃的副作用作用域, 和之前我们创建的作用域对比, 发现getCurrentScope 获取的就是我们创建的effect作用域.

其实每一个组件都有一个effect作用域, 用于收集组件内所有的副作用. 组件更新函数本身也就是一个副作用. 这也就是响应式数据变化后, 页面会重新渲染的原因.

以及组件被销毁后, vue3 会通过组件的effect作用域清理组件内收集的所有副作用

该API 在工作中并不常使用到. 甚至一个项目里连一次都不会用到.

6. onScopeDispose

该API 函数主要用于调试, 工作中也不怎么常用, 其作用就是在当前活跃的副作用(effect)作用域对象上注册一个调试的回调函数. 在effect作用域关闭时, 会自动调用注册的回调函数,.

示例:

// 创建副作用作用域
const scope = effectScope();
console.log("scope", scope);

// 收集运行的副作用
scope.run(() => {
  // 计算属性副作用
  const computedCount = computed(() => count.value * 2);

  // watch 侦听副作用
  watch(count, () => {
    console.log("computedCount", computedCount.value);
    console.log("watch count", count.value);
  });

  // watchEffect 副作用
  watchEffect(() => {
    console.log("watchEffect count", count.value);
  });

  // 在当前活跃的 effect 作用域对象上注册一个回调函数
  onScopeDispose(() => {
    console.log("当前effectScope 停止");
  });
});

// 2秒以后关闭所有的副作用
setTimeout(() => {
  scope.stop();
}, 2000);

示例中, 我们在effectScope收集副作用时, 通过onScopeDispose函数注册了一个回调函数.

effectScope副作用作用域, 即scope对象调用stop方法时, 会自动执行注册的回调函数. 多用于功能调试

7. 结语

至此, 就把vue3中响应式进阶API 中剩余的API函数给大家讲完了, 这里比较常用的API 有triggerRef, toRaw, markRaw, effectScope, 其余两个API 函数并不怎么常用.

这里尤其要注意effectScope, 使用好了可以给代码增色不少.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/637943.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言/数据结构——每日一题(设计循环队列)

一.前言 上一次我们分享了关于队列的基本实现——https://blog.csdn.net/yiqingaa/article/details/139033067?spm1001.2014.3001.5502 现在我们将使用队列知识来解决问题——设计循环队列&#xff1a;https://leetcode.cn/problems/design-circular-queue/submissions/533299…

振弦式渗压计的维护和校准:确保数据准确性的关键步骤

振弦式渗压计是一种用于测量土壤和岩石中孔隙水压力的高精度仪器。它广泛应用于土木工程、水利工程、地质灾害监测等领域&#xff0c;准确性直接影响到工程安全和监测数据的可靠性。因此&#xff0c;对振弦式渗压计进行适当的维护和校准是至关重要的。本文将探讨振弦式渗压计的…

2024-5-6-从0到1手写配置中心Config之实现配置中心客户端

配置加载原理 在Spring中PropertySource类实现了所有属性的实例化。 启动赋值&#xff1a; 定义自定义属性配置源&#xff0c;从config-server获取全局属性&#xff1b;Spring启动时&#xff0c;插入自定义属性配置源&#xff1b;绑定属性会优先使用&#xff0c;给自定义属性…

tomcat jdbc连接池的默认配置配置方案

MySQL 5.0 以后针对超长时间数据库连接做了一个处理&#xff0c;即一个数据库连接在无任何操作情况下过了 8 个小时后(MySQL 服务器默认的超时时间是 8 小时)&#xff0c;MySQL 会自动把这个连接关闭。在数据库连接池中的 connections 如果空闲超过 8 小时&#xff0c;MySQL 将…

python期末作业:批量爬取站长之家的网站排行榜数据并保存,数据分析可视化

爬虫作业,含python爬取数据和保存文件,数据分析使用pyecharts做数据可视化 整体上分析网站的排名,直观看各个网站的热度。 数据分析之后大致的效果: 整个项目分为两个大的部分,第一部分就是抓取网站排名数据,然后保存为Excel、csv等格式,其次就是从文件中…

Advanced Installer 使用教程-自定义操作(下)

1、点击左侧“必要条件”&#xff0c;选择“运行环境” 2、这个运行环境用于设置安装前、中、后&#xff0c;各个阶段的自定义操作 3、安装过程中的自定义操作 1&#xff09;右击基本特征&#xff0c;选择新建程序包先决条件&#xff0c;在弹出的对话框中选择自己的EXE任务程…

Live800:客户为王,企业竞争的新趋势与核心要素!

在企业经营管理中&#xff0c;客户始终是最重要的资源和战略。从企业经营的角度来说&#xff0c;企业管理的核心是客户管理&#xff0c;客户管理的核心是价值创造和价值分配&#xff0c;这是企业经营的基础。这里主要讨论了企业竞争的新趋势与核心要素&#xff0c;认为客户为王…

营收净利双降、股东减持,大降价也救不了良品铺子

号称“高端零食第一股”的良品铺子(603719.SH)&#xff0c;正遭遇部分股东的“用脚投票”。 5月17日晚间&#xff0c;良品铺子连发两份减持公告&#xff0c;其控股股东宁波汉意创业投资合伙企业、持股5%以上股东达永有限公司&#xff0c;两者均计划减持。 其中&#xff0c;宁…

【minio】minio文件访问不到问题记录

问题描述&#xff1a; 项目上上传了logo&#xff0c;但是无法回写logo&#xff0c;但是文件minio路径已经返回&#xff0c;并且到minio服务器上也能下载文件&#xff1b; 解决方案&#xff1a; 1.排查Nginx的代理的minio是否正确 2.登录minio服务查一下文件路径policy是否设置访…

国内大模型价格战全面爆发:新旧势力逐鹿江湖【附主流模型价格对比】

近年来&#xff0c;随着人工智能技术的不断发展&#xff0c;大模型逐渐成为行业的焦点。然而&#xff0c;伴随而来的却是一场价格战。DeepSeek率先推出超低价服务&#xff0c;随后字节跳动、阿里巴巴、百度、科大讯飞、腾讯等巨头纷纷跟进&#xff0c;使得这一领域的竞争愈演愈…

研发机构大数据迁移如何保障敏感数据不泄露

随着云计算和大数据技术的飞速进步&#xff0c;越来越多的企业正试图通过数据迁移来提升IT基础设施的效率&#xff0c;减少成本&#xff0c;并增强业务的灵活性。但是&#xff0c;这一过程并非没有它的挑战&#xff0c;尤其是在数据安全方面。数据在转移过程中可能会遭遇黑客攻…

Python使用thread模块实现多线程

介绍&#xff1a; 线程&#xff08;Threads&#xff09;是操作系统提供的一种轻量级的执行单元&#xff0c;可以在一个进程内并发执行多个任务。每个线程都有自己的执行上下文&#xff0c;包括栈、寄存器和程序计数器。 在Python中&#xff0c;可以使用threading模块创建和管理…

设计模式5——抽象工厂模式

写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用&#xff0c;主要是下面的UML图可以起到大作用&#xff0c;在你学习过一遍以后可能会遗忘&#xff0c;忘记了不要紧&#xff0c;只要看一眼UML图就能想起来了。同时也请大家多多指教。 抽象工厂模式&#xff08;Abst…

Docker+nginx部署SpringBoot+vue前后端分离项目(保姆及入门指南)

前后分离项目部署 项目回顾工具上线准备1、win1.1、前端1.2、后端 2、linux环境2.1、安装docker2.2、安装docker compose2.3、编写Dockerfile文件2.4、编写docker-compose.yml文件2.5、修改application-pro.yml2.6、准备好nginx的挂载目录和配置2.7、部署后端服务 项目回顾 书…

Pod容器资源限制和探针

目录 一、资源限制 1.Pod和容器的资源请求和限制 2.CPU 资源单位 案例一 案例二 二、健康检查&#xff0c;又称为探针&#xff08;Probe&#xff09; 1.探针的三种规则 2.Probe支持三种检查方法 3.探测获得的三种结果 案例一&#xff1a;exec 案例二&#xff1a;htt…

C语言/数据结构——每日一题(有效的括号)

一.前言 如果想要使用C语言来解决这道题——有效的括号&#xff1a;https://leetcode.cn/problems/valid-parentheses/description/我们必须要借用上一篇我们所讲的内容——栈的实现&#xff1a;https://blog.csdn.net/yiqingaa/article/details/138923750?spm1001.2014.3001.…

LLM实战:当网页爬虫集成gpt3.5

1. 背景 最近本qiang~关注了一个开源项目Scrapegraph-ai&#xff0c;是关于网页爬虫结合LLM的项目&#xff0c;所以想一探究竟&#xff0c;毕竟当下及未来&#xff0c;LLM终将替代以往的方方面面。 这篇文章主要介绍下该项目&#xff0c;并基于此项目实现一个demo页面&#x…

【linux】深入了解线程池:基本概念与代码实例(C++)

文章目录 1. 前言1.1 概念1.2 应用场景1.3 线程池的种类1.4 线程池的通常组成 2. 代码示例2.1 log.hpp2.2 lockGuard.hpp① pthread_mutex_t 2.3 Task.hpp2.4 thread.hpp2.5 threadPool.hpp① 基本框架② 成员变量③ 构造函数④ 其余功能函数&#xff1a; main.cc结果演示 完整…

车载网络测试实操源码_使用CAPL脚本模拟发送符合协议要求(Counter和CRC)的CAN报文

系列文章目录 车载网络测试实操源码_使用CAPL脚本解析hex、S19、vbf文件 车载网络测试实操源码_使用CAPL脚本对CAN报文的Counter和CRC进行实时监控 车载网络测试实操源码_使用CAPL脚本模拟发送符合协议要求(Counter和CRC)的CAN报文 车载网络测试实操源码_使用CAPL脚本实现安全…

Go语言实现人脸检测(Go的OpenCV绑定库)

文章目录 OpenCVGithub官网安装环境变量 Go的OpenCV绑定库Github文档安装搜索视频设备ID显示视频检测人脸 OpenCV Github https://github.com/opencv/opencv/ 官网 https://opencv.org/ 安装 brew install opencv brew upgrade opencv安装目录 cd /usr/local/opt/opencv…