Vue3 之 reactive、ref、toRef、toRefs 使用与区别,源码分析详细注释
reactive、ref、toRef、toRefs 使用与区别
reactive
- 参数传入普通对象,不论层级多深都可以返回响应式对象,(参数只能是对象)
- 但是解构、扩展运算符会失去响应式
ref 作用及用法
- 参数可以为任意类型,推荐使用基本类型
- 使用时 需要通过
xxx.value
的形式获取 - 本质是
拷贝粘贴
一份数据,脱离了与源数据的交互 - 将对象中属性变成响应式数据,修改该数据是不会影响到源数据,但是会更新视图
<template>
<div id="contain">
{{ refTest }}
<button @click="change">click</button>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
const hello = "hello"; // 源数据
const refTest = ref(hello); // 相当于复制了一份
function change() {
refTest.value = "world"; // 会更新视图
console.log(refTest);
console.log(hello); // 源数据不变 hello
}
</script>
toRef 作用及用法
- 针对 reactive 解构失去响应式的问题,创建了 toRef,用于为源响应式对象上的属性新建一个 ref,保持对源对象属性的响应式交互。
- 语法:
toRef(target, key)
- 使用时 需要通过
xxx.value
的形式获取 - 本质是引用,与源数据有交互,修改该数据是会影响源数据,但是不会更新视图,如果需要更新视图,需要使用 reactive 包裹源数据
<template>
<div id="contain">
<p>{{ toRefTest }} <button @click="changeNor">click</button></p>
<p>{{ toRefReactTest }} <button @click="changeRea">click</button></p>
</div>
</template>
<script lang="ts" setup>
import { reactive, toRef } from "vue";
// 普通对象
const state = { name: "hello" }; // 源数据
const toRefTest = toRef(state, "name"); // toRef 本质是引用
function changeNor() {
toRefTest.value = "world"; // 不会更新视图
console.log(state); // 会影响源数据
}
// ------------------------------------------
// reactive 包裹源数据
const reactState = reactive({ name: "hello" }); // reactive 包裹源数据
const toRefReactTest = toRef(reactState, "name");
function changeRea() {
toRefReactTest.value = "world"; // 会更新视图
console.log(reactState); // 会影响源数据
}
</script>
toRefs 作用及用法
- 就是批量的 toRef 操作,toRefs 是一次性将 reactive 中的所有属性都转为 ref
- 语法:
toRefs(target)
- 同样可以用于解构 reactive 的响应式对象
- 使用时 需要通过
xxx.value
的形式获取 - 本质是引用,与源数据有交互,修改该数据是会影响源数据,但是不会更新视图,如果需要更新视图,需要使用 reactive 包裹源数据
<template>
<div id="contain">
<p>
普通对象:{{ name }} -- {{ age }}
<button @click="changeNor">click</button>
</p>
<p>
reactive对象:{{ rename }} -- {{ reage
}}<button @click="changeRea">click</button>
</p>
</div>
</template>
<script lang="ts" setup>
import { reactive, toRefs } from "vue";
// 普通对象
const state = { name: "hello", age: 18 }; // 源数据
const { name, age } = toRefs(state); // 本质是引用
function changeNor() {
name.value = "world"; // 不会更新视图
age.value++;
console.log(state); // 会影响源数据
}
// ------------------------------------------
// reactive 包裹源数据
const reactState = reactive({ rename: "hello", reage: 18 }); // reactive 包裹源数据
const { rename, reage } = toRefs(reactState); // 本质是引用
function changeRea() {
rename.value = "world"; // 会更新视图
reage.value++;
console.log(reactState); // 会影响源数据
}
</script>
ref,toRef,toRefs 源码实现解析详细注释
ref 和 reactive 的底层原理区别: reactive 内部采用 proxy ,而 ref 中内部采用的是 defineProperty
ref、shallowRef 源码实现。使用class RefImpl
实现,会被 babel 编译成defineProperty
其中 share.ts 和 reactive.ts 文件中的方法,不在赘述,详见上一篇 响应式原理的文章
import { hasChanged, isArray, isObject } from "./shared";
import { TrackOpTypes, TriggerOrTypes } from "./shared";
import { track, trigger } from "./effect";
import { reactive } from "./reactive";
export function ref(value) {
return createRef(value);
}
// shallowRef 只能处理基本类型数据
export function shallowRef(value) {
return createRef(value, true);
}
const convert = (val) => (isObject(val) ? reactive(val) : val);
class RefImpl {
public _value;
public __v_isRef = true; // 实例添加 __v_isRef, 表示是一个ref属性
constructor(public rawValue, public shallow) {
// 1.参数前面加修饰符 表示实例属性
this._value = shallow ? rawValue : convert(rawValue); // 如果是深度监听 需要把里面的都变成响应式的
}
// 2. 类的属性访问器
get value() {
// 3. 依赖收集 代理取值取_value
track(this, TrackOpTypes.GET, "value"); // 依赖收集
return this._value;
}
set value(newValue) {
// 4. 判断老值和新值是否有变化
if (hasChanged(newValue, this.rawValue)) {
this.rawValue = newValue; // 新值会作为老值
this._value = this.shallow ? newValue : convert(newValue);
// 5. 触发更新
trigger(this, TriggerOrTypes.SET, "value", newValue);
}
}
}
function createRef(rawValue, shallow = false) {
return new RefImpl(rawValue, shallow);
}
toRef,toRefs 源码实现。使用class ObjectRefImpl
实现,会被 babel 编译成defineProperty
class ObjectRefImpl {
public __v_isRef = true; // 实例添加 __v_isRef, 表示是一个ref属性
constructor(public target, public key) {}
get value() {
return this.target[this.key]; // 如果原对象是响应式的就会依赖收集
}
set value(newValue) {
this.target[this.key] = newValue; // 如果原来对象是响应式的 那么就会触发更新
}
}
// 将对象的某一个值转化成 ref类型
export function toRef(target, key) {
return new ObjectRefImpl(target, key);
}
// 可能传递的是一个数组 或者对象,属性全部转化成 ref类型
export function toRefs(object) {
const ret = isArray(object) ? new Array(object.length) : {};
for (let key in object) {
ret[key] = toRef(object, key); // 遍历调用toRef方法
}
return ret;
}
Vue3 之 reactive、ref、toRef、toRefs 使用与区别,源码分析详细注释的更多相关文章
- Vue3中的响应式对象Reactive源码分析
Vue3中的响应式对象Reactive源码分析 ReactiveEffect.js 中的 trackEffects函数 及 ReactiveEffect类 在Ref随笔中已经介绍,在本文中不做赘述 本 ...
- Vue.js 源码分析(十) 基础篇 ref属性详解
ref 被用来给元素或子组件注册引用信息.引用信息将会注册在父组件的 $refs 对象上.如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素:如果用在子组件上,引用就指向组件实例,例如: ...
- Vue3源码分析之 Ref 与 ReactiveEffect
Vue3中的响应式实现原理 完整 js版本简易源码 在最底部 ref 与 reactive 是Vue3中的两个定义响应式对象的API,其中reactive是通过 Proxy 来实现的,它返回对象的响应 ...
- Vue3源码分析之Diff算法
Diff 算法源码(结合源码写的简易版本) 备注:文章后面有详细解析,先简单浏览一遍整体代码,更容易阅读 // Vue3 中的 diff 算法 // 模拟节点 const { oldVirtualDo ...
- Vue3源码分析之微任务队列
参考资料:https://zh.javascript.info/microtask-queue#wei-ren-wu-dui-lie-microtaskqueue 简化版 Vue3 中的 微任务队列实 ...
- Spring boot加载REACTIVE源码分析
一,加载REACTIVE相关自动配置 spring boot通过判断含org.springframework.web.reactive.DispatcherHandler字节文件就确定程序类型是REA ...
- petite-vue源码剖析-逐行解读@vue/reactivity之reactive
在petite-vue中我们通过reactive构建上下文对象,并将根据状态渲染UI的逻辑作为入参传递给effect,然后神奇的事情发生了,当状态发生变化时将自动触发UI重新渲染.那么到底这是怎么做到 ...
- Vue3全局APi解析-源码学习
本文章共5314字,预计阅读时间5-15分钟. 前言 不知不觉Vue-next的版本已经来到了3.1.2,最近对照着源码学习Vue3的全局Api,边学习边整理了下来,希望可以和大家一起进步. 我们以官 ...
- ref、reactive、toRef、toRefs使用与区别
reactive 传参:reactive(arg),arg只能是对象 arg为普通对象 返回响应式对象,不管层级多深,都能响应 使用:获取数据值的时候直接获取,不需要加.value 特点:解构.扩展运 ...
- 全面了解Vue3的 reactive 和相关函数
Vue3的 reactive 怎么用,原理是什么,官网上和reactive相关的那些函数又都是做什么用处的?这里会一一解答. ES6的Proxy Proxy 是 ES6 提供的一个可以拦截对象基础操作 ...
随机推荐
- winform——windows 服务的安装 卸载 启动 停止
安装服务和卸载服务采用process启动命令行的方式.启动服务和停止服务用到了 System.ServiceProcess.ServiceController这个类. 程序是这样运行的,首先启动服 ...
- FFmpeg开发笔记(二十三)使用OBS Studio开启RTMP直播推流
OBS是一个开源的直播录制软件,英文全称叫做Open Broadcaster Software,广泛用于视频录制.实时直播等领域.OBS不但开源,而且跨平台,兼容Windows.Mac OS.Lin ...
- Hibernate双向关联导致Java对象转换为JSON字符串时死循环问题的分析与解决方案
引言: 本文描述了在SSH框架中,多个持久层对象相互引用,从而引发分页查询中,查询所得的持久化对象转换为JSON字符串报错的原因及解决方案 使用EasyUI框架的小伙伴们都知道,在使用datagrid ...
- 查看CentOS版本的方法
1.以下命令对于Linux发行版是通用的: root@MyMail ~ # uname Linux root@MyMail ~ # uname -r 2.6.18-164.el5 [root@loca ...
- itest work 开源接口测试&敏捷测试管理平台 9.5.0 GA_u3,优化及修复关键 BUG
(一)itest work 简介 itest work (爱测试) 一站式工作站让测试变得简单.敏捷,"好用.好看,好敏捷" ,是itest wrok 追求的目标.itest w ...
- .NET周刊【6月第1期 2024-06-02】
国内文章 一文带你了解.NET能做什么? https://www.cnblogs.com/Can-daydayup/p/18214473 .NET是一个免费.开源.跨平台的开发平台框架,广泛应用于桌面 ...
- OPA Gatekeeper:Kubernetes的策略和管理
目录 一.系统环境 二.前言 三.OPA Gatekeeper简介 四.在kubernetes上安装OPA Gatekeeper 五.gatekeeper规则 5.1 使用gatekeeper禁止某些 ...
- react类组件 组件传值
class Cmp1 extends React.Component{ render(){ return ( <div>{ this.props.name } -- 我是一个类</d ...
- C#.NET Winform承载WCF RESTful API (硬编码配置)
1.新建一个名为"WindowsForms承载WCF"的WINFORM程序. 2.在解决方案里添加一个"WCF 服务库"的项目,名为"WcfYeah& ...
- Windows 预览体验计划显示空白
Open PowerShell as Administator.In the elevated PowerShell window, copy and paste the following comm ...