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

  • 该文章是在学习 小满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 !!
 *
 */
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值