Vue3 —— ref 全家桶及源码学习

news2024/11/29 10:34:10
  • 该文章是在学习 小满vue3 课程的随堂记录
  • 示例均采用 <script setup>,且包含 typescript 的基础用法

前言

本章 ref 全家桶 主要包括以下几个api 和 对应源码的学习:

  • ref
  • isRef
  • shallowRef
  • triggerRef
  • customRef

一、api 各自的使用

1、ref

  • 使用 vue3 定义响应式数据 主要通过 refreactive
  • ref 可定义 任何类型数据,reactive 用来定义对象类型
  • ref 定义的数据,修改时要通过 .value,template 中使用时不需要 .value
  • ref 也可以用来 获取dom:dom上绑定 ref 属性,并用 ref 创建同名的响应式变量

① 基本使用

<div>{{ name }}</div>
import { ref, Ref } from "vue"

const name: Ref<string> = ref('xiaoman');
name.value = 'blue'

② 获取dom

<div ref="dom">我是dom</div>
<button @click="getDom">获取dom</button>
import { ref } from "vue"
const dom = ref<HTMLElement>();
function getDom() {
  // ?.的形式,先判断再获取
  console.log(dom.value?.innerText);
}

在这里插入图片描述

2、isRef

字如其意,就是 判断一个变量是不是 ref 类型的响应式数据,返回布尔值

import { ref, Ref, isRef } from "vue"

const name: Ref<string> = ref('xiaoman');
name.value = 'blue'

console.log(isRef(name)); // true

3、shallowRef

  • ref 深层 的响应式 ,shallowRef浅层 的响应式
  • 深层 的响应式:不管怎么修改都会 直接触发视图更新
  • 浅层 的响应式:修改 深层数据 时,数据修改成功,但 不会立刻更新视图
  • 若同时修改 ref 和 shallowRef 的数据,shallowRef 的视图会被顺带更新,所以不要同时使用!

① 该例子中,ref 被修改后,会立刻触发视图的更新

<div>Man:{{ Man }}</div>
<button @click="changeMan">改变ref</button>
import { ref, Ref } from "vue"

// 使用 type 定义类型
type M = {
  name: string;
};
const Man: Ref<M> = ref({ name: "小满" });

function changeMan() {
   Man.value.name = "大满1";
}

② 该例子中,shallowRef 被修改后,数据打印显示更新,但不会更新视图

<div>Man2:{{ Man2 }}</div>
<button @click="changeMan">改变ref</button>
import { shallowRef, ShallowRef } from "vue"

// 使用 type 定义类型
type M = {
  name: string;
};
const Man2: ShallowRef<M> = shallowRef({ name: "小满" });

function changeMan() {
   Man2.value.name = "大满2";
   // 这里打印更新,但是不更新视图
  console.log("Man2.value.name", Man2.value.name); 
}

控制台打印数据已更新:

在这里插入图片描述

但视图未更新:
在这里插入图片描述

③ 若将 ref 和 shallowRef 同时更新,shallowRef 的视图也会被顺带更新

<div>Man:{{ Man }}</div>
<div>Man2:{{ Man2 }}</div>
<button @click="changeMan">改变ref</button>
import { ref, Ref, shallowRef, ShallowRef } from "vue"

// 使用 type 定义类型
type M = {
  name: string;
};
const Man: Ref<M> = ref({ name: "小满" });
const Man2: ShallowRef<M> = shallowRef({ name: "小满" });

function changeMan() {
   Man.value.name = "大满1";
   Man2.value.name = "大满2";
}

视图全部更新:

在这里插入图片描述

4、triggerRef

  • 作用:强制触发视图的更新
  • ref 在源码中 会调用 triggerRef 进行视图的 强制更新,这也就是 ref 和 shallowRef 混用时 shallowRef 视图也会被更新的原因

我们使用 shallowRef + triggerRef 看看效果:

<div>Man2:{{ Man2 }}</div>
<button @click="changeMan">改变ref</button>
import { shallowRef, ShallowRef, triggerRef } from "vue"

// 使用 type 定义类型
type M = {
  name: string;
};
const Man2: ShallowRef<M> = shallowRef({ name: "小满" });

function changeMan() {
   Man2.value.name = "大满2";
   triggerRef(Man2);
}

果然,视图更新:

在这里插入图片描述

5、customRef

  • 作用:用来 自定义 ref
  • 接收一个函数
    • 函数有 两个参数track 收集变化trigger 触发更新
    • 函数 返回一个对象,里面自定义 getset 函数。get 中先收集变化再返回值set 中先设置新值再触发更新

① 先来写一个自定义ref

<div>custom:{{ custom }}</div>
<button @click="change">改变customRef</button>
import { customRef } from "vue"

function MyRef<T>(value: T) {
  return customRef((track, trigger) => {
    return {
      get() {
        track();
        return value;
      },
      set(newVal) {
        value = newVal;
        console.log("触发set");
        trigger();
      },
    };
  });
}

const custom = MyRef<string>("xiaoman");
function change() {
  custom.value = "daman";
}

点击后视图会立刻更新:

在这里插入图片描述

② 考虑到快速点击的场景,给 MyRef 函数做一下防抖

function MyRef<T>(value: T, delay = 500) {
  let timer: any = null;
  return customRef((track, trigger) => {
    return {
      get() {
        track();
        return value;
      },
      set(newVal) {
        clearTimeout(timer);
        timer = setTimeout(() => {
          console.log("触发set", newVal);
          value = newVal;
          trigger();
        }, delay);
      },
    };
  });
}

二、源码学习

  • 不同的项目初始化方式,源码的位置可能不同(我是采用 vite 创建的项目)
  • 源码位置我查阅的是:node_modules/@vue/reactivity/dist/reactivity.cjs.prod
  • 主要学习一下核心函数 createRef 基本逻辑

① 源码截图:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

② 源码学习记录

/**
 *  createRef 中
 *    1、若 isRef = true,则直接返回;否则走进 RefImpl(实现 ref 的类)中
 *
 *    2、RefImpl:跟上面的 customRef 非常类似,原理相同(get\set,track\trigger)
 *
 *        - get 时要追踪变化,trackRefValue(依赖收集)
 *        - set 时要触发更新,triggerRefValue -> triggerEffects(依赖更新)
 *
 *            ref 和 triggerRef 在源码中都会调用 triggerRefValue -> triggerEffects,所以都会触发更新
 *            所以 ref 不能和 shallowRef 混用!会导致 shallowRef 被更新
 *
 *    3、若 shallow 传 true(即为shallowRef)
 *          - _rawValue 直接返回
 *          - _value 直接返回
 *
 *    4、若 shallow 传 false(即为 ref)
 *          - _rawValue 走进 toRaw 中(后续学习)
 *          - _value 则会走进 toReactive 中,toReactive 中先判断是不是引用类型,
 *                - 如果是的话调用 toReactive 函数将其变为响应式对象
 *                - 如果不是直接返回
 *          - 相当于 ref 内部实现响应式还是用的 reactive !!
 *
 */

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【雕爷学编程】Arduino动手做(04)---震动传感器模块3

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

Word转PDF在线转换如何操作?分享转换技巧

现如今&#xff0c;pdf转换器已成为大家日常办公学习必不可少的工具&#xff0c;市场上的pdf转换器主要有两种类型&#xff0c;一种是需要下载安装的&#xff0c;另一种是网页版&#xff0c;打开就可以使用的&#xff0c;今天小编给大家推荐一个非常好用的网页版pdf转换器&…

【解决问题】手动执行maven命令安装指定jar包到本地仓库

背景&#xff1a; 有一个三方jar从远程仓库始终没有拉下来&#xff0c;没办法只能自己去下载&#xff0c;但是自己下载下来&#xff0c;不能直接建立个目录放到本地仓库&#xff0c;需要执行命令才行 操作 命令&#xff1a; mvn install:install-file -DgroupIdcom.alipay …

Java【Spring】使用类注解和方法注解, 更简单的存储和获取 Bean

文章目录 前言一、存储 Bean1, 配置文件2, 五大类注解Bean 的命名规则 3, 方法注解Bean 的命名规则 二、获取 Bean1, 属性注入2, Setter 注入3, 构造方法注入4, Autowired 和 Resource 的区别5, 同一个类型的多个 Bean 注入问题 总结 前言 各位读者好, 我是小陈, 这是我的个人主…

「2024」预备研究生mem-论证推理强化:评价类

一、论证推理强化&#xff1a;评价类 二、课后题

解决: git拉取报错 git 未能顺利结束 (退出码 1)

拉取代码失败信息 解决方法: 执行一下"git push -f origin master"命令即可 步骤: 1.项目文件夹右击选择"Git Bash Here",打开命令窗口 2. 输入"git push -f origin master"后,回画 执行结束 3.再拉取代码,成功

【数学建模】-- Matlab中图的最短路径

前言&#xff1a; 图的基本概念&#xff1a; 若想简单绘制图可以利用此网站&#xff1a; 左上角Undirected/Directed是无向图/有向图 左边 0-index &#xff0c;1-index为0下标&#xff0c;1下标。 Node Count为节点个数 Graph Data&#xff1a;最初尾节点的名称&#xff…

从初学者的角度来理解指针常量和常量指针

重新理解指针常量&#xff0c;常量指针 应用 我先提一个问题&#xff1a;知道指针常量&#xff0c;常量指针存在的作用是什么吗&#xff1f; 先了解它们存在的作用再去理解它们&#xff0c;或许更轻松些。 比如配置文件读取&#xff1a;在许多工程中&#xff0c;配置文件用于…

linux 下 网卡命名改名

Linux 操作系统的网卡设备的传统命名方式是 eth0、eth1、eth2等&#xff0c;而 CentOS7 提供了不同的命名规则&#xff0c;默认是网卡命名会根据网卡的硬件信息&#xff0c;插槽位置等有关&#xff1b;来分配。这样做的优点是命名全自动的、可预知的&#xff0c;缺点是比 eth0、…

计算机服务器被360后缀勒索病毒攻击怎么办,勒索病毒解密

计算机技术的不断发展&#xff0c;不仅方便了企业的生产生活&#xff0c;也为社会的发展带来了巨大贡献&#xff0c;但随之而来的网络威胁也不断增加&#xff0c;勒索病毒就是其中较为常见的常见的威胁。近期&#xff0c;我们收到很多企业的求助&#xff0c;企业的计算机服务器…

volatile,解决内存可见性引起的问题,wait和notify

补充&#xff1a;synchronized&#xff08;务必会读&#xff08;辛可肉耐子&#xff09;会写&#xff09;&#xff0c;要搭配一个对象的时候&#xff0c;不一定非要是访问的this成员 synchronized(锁对象&#xff09;{ 代码块} public synchronized static void func(){} 静态方…

JS+CSS实现内凹导航栏

在移动互联网时代&#xff0c;导航栏是一个非常重要的元素&#xff0c;它能够帮助用户快速找到所需的信息。下面使用JS CSS实现一个内凹导航栏&#xff0c;内凹导航栏则是一种比较流行的设计风格&#xff0c;它能够让导航栏看起来更加立体和美观&#xff0c;视觉效果也非常不错…

vue : 无法加载文件 C:\Users\…\npm\vue.ps1,因为在此系统上禁止运行脚本。

在 PowerShell 中创建 vue 项目时&#xff0c;出现了以下错误导致创建失败&#xff1a;vue : 无法加载文件 C:\Users\…\npm\vue.ps1&#xff0c;因为在此系统上禁止运行脚本。 报错原因 用户权限不足导致无法加载文件&#xff0c;以管理员身份运行终端或者 PowerShell 也可…

使用Three.js制作一个旋转多面体

之前一直对three.js比较好奇&#xff0c;但是一直没有着手学习。今天刷到一篇博客&#xff08;博主&#xff1a;1_bit&#xff09;&#xff0c;觉得挺有意思&#xff0c;就跟着敲了一下。 html: 其中canvas用于添加渲染好的元素&#xff0c;本篇文章通过CDN形式引入three.js,…

2023 Gartner RPA魔力象限报告解读:国产厂商“破纪录”跃升意味着什么?

2023 Gartner RPA魔力象限报告解读&#xff1a;象限跃升彰显国产RPA厂商实力 2023 Gartner RPA魔力象限报告四大行业趋势&#xff0c;国产RPA厂商已在践行 文/王吉伟 8月3日&#xff0c;全球著名咨询调查机构Gartner发布了《2023年全球RPA魔力象限&#xff08;Gartner RPA M…

ceph相关概念和部署

Ceph 可用于向云提供 Ceph 对象存储 平台和 Ceph 可用于提供 Ceph 块设备服务 到云平台。Ceph 可用于部署 Ceph 文件 系统。所有 Ceph 存储集群部署都从设置 每个 Ceph 节点&#xff0c;然后设置网络。 Ceph 存储集群需要满足以下条件&#xff1a;至少一个 Ceph 监控器&#x…

10分钟学会阿里OSS对象存储

一. 前言 最近有很多小伙伴问&#xff0c;如果我们要进行大规模的文件存储该怎么做? 其实实现文件存储的技术有很多&#xff0c;如果我们在网上搜索一下&#xff0c;你会发现实现的技术简直是五花八门&#xff0c;比如有一种技术叫FastDFS就可以实现文件存储&#xff0c;但该…

Effective Java笔记(31)利用有限制通配符来提升 API 的灵活性

参数化类型是不变的&#xff08; invariant &#xff09; 。 换句话说&#xff0c;对于任何两个截然不同的类型 Typel 和 Type2 而言&#xff0c; List<Type1 &#xff1e;既不是 List<Type 2 &#xff1e; 的子类型&#xff0c;也不是它的超类型 。虽然 L ist<String…

问道管理:零基础学炒股?

跟着股市的不断升温&#xff0c;越来越多的人参加到了炒股大军中&#xff0c;希望经过股市赚到更多的金钱。但是关于零根底的新手来说&#xff0c;怎么开始学习炒股成为了一个难题。那么&#xff0c;零根底学炒股真的难吗&#xff1f;怎么更好的入门和学习&#xff1f; 首要&am…

线性代数(三) 线性方程组

前言 如何利用行列式&#xff0c;矩阵求解线性方程组。 线性方程组的相关概念 用矩阵方程表示 齐次线性方程组&#xff1a;Ax0&#xff1b;非齐次线性方程组&#xff1a;Axb. 可以理解 齐次线性方程组 是特殊的 非齐次线性方程组 如何判断线性方程组的解 其中R(A)表示矩阵A的…