首页 > 编程语言 >vue3源码-三、ref和toRefs的实现

vue3源码-三、ref和toRefs的实现

时间:2023-05-06 22:22:18浏览次数:38  
标签:toRefs return object value newVal 源码 ._ ref

实现Ref

ref的本质就是通过类属性访问器来实现,可以将一个普通值类型进行包装

import { hasChanged, isObject } from "@vue/shared";
import { track, trigger } from "./effect";
import { TrackOpTypes, TriggerOpTypes } from "./operations";
import { reactive } from "./reactive";

export function ref(value) { // ref Api
 return createRef(value);
}

export function shallowRef(value) { // shallowRef Api
 return createRef(value, true);
}
function createRef(rawValue, shallow = false) {
 return new RefImpl(rawValue, shallow)
}

const convert = (val) => isObject(val) ? reactive(val) : val; // 递归响应式

// 实现类
class RefImpl {
 private _value; // 保存值
 public readonly __v_isRef = true; // 标识是ref
 constructor(private _rawValue, public readonly _shallow) {
     // 初始化value
     this._value = _shallow ? _rawValue : convert(_rawValue)
 }
 get value() {
     // 依赖收集
     track(this, TrackOpTypes.GET, 'value');
     return this._value;
 }
 set value(newVal) {
     if (hasChanged(newVal, this._rawValue)) {
         this._rawValue = newVal; // 保存值
         this._value = this._shallow ? newVal : convert(newVal);
         // 触发更新
         trigger(this, TriggerOpTypes.SET, 'value', newVal);
     }
 }
}

实现toRefs

使用:将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的ref。每个单独的ref都是使用 toRef()创建的。

const state = reactive({
foo: 1,
bar: 2
})

const stateAsRefs = toRefs(state)
/*
stateAsRefs 的类型:{
foo: Ref<number>,
bar: Ref<number>
}
*/

// 这个 ref 和源属性已经“链接上了”
state.foo++
console.log(stateAsRefs.foo.value) // 2

stateAsRefs.foo.value++
console.log(state.foo) // 3

// 解构使用
function useFeatureX() {
const state = reactive({
 foo: 1,
 bar: 2
})

// ...基于状态的操作逻辑

// 在返回时都转为 ref
return toRefs(state)
}

// 可以解构而不会失去响应性
const { foo, bar } = useFeatureX()



class ObjectRefImpl{
 public readonly __v_isRef = true
 constructor(private readonly _object, private readonly _key) {}
 get value(){
     return this._object[this._key]
 }
 set value(newVal){
     this._object[this._key] = newVal
 }
}
export function toRef(object,key){
 return new ObjectRefImpl(object,key);
}
export function toRefs(object) {
 const ret = isArray(object) ? new Array(object.length) : {};
 for (const key in object) {
     ret[key] = toRef(object, key)
 }
 return ret;
}

这样就可以将对象的属性转化为ref属性。

标签:toRefs,return,object,value,newVal,源码,._,ref
From: https://www.cnblogs.com/dgqp/p/17378587.html

相关文章

  • LinkedList底层结构和源码
    LinkedList底层结构和源码LinkedList的全面说明LinkedList底层实现了双向链表和双端队列特点可以添加任意元素(元素可以重复,包括null)线程不安全,没有实现同步LinkedList的底层操作机制LinkedList底层维护了一个双向链表LinkedList中维护了两个属性first和last分别......
  • ArrayList底层结构和源码分析
    ArrayList底层结构和源码分析ArrayList的底层操作机制源码分析ArrayList中维护了一个Object类型的数组elementDatatransientObiect[]elementData;//transient是瞬间短暂的,表示被它修饰的属性不被序列化当创建ArrayList对象是,如果使用的是无参构造器,那么初始elementD......
  • RocketMQ之消息发送源码分析
    一、概述负责生产消息,一般由业务系统负责生产消息。一个消息生产者会把业务应用系统里产生的消息发送到broker服务器。RocketMQ支持三种消息发送方式:同步消息发送(sync):当Producer发送消息到Broker时会同步等待消息处理结果;异步消息发送(async):当Producer发送消息到Broker时......
  • RocketMQ之消息接收源码分析
    一、概述对于任何一款消息中间件而言,消费者客户端一般有两种方式从消息中间件获取消息并消费:Push方式:由消息中间件(MQ消息服务器代理)主动地将消息推送给消费者;采用Push方式,可以尽可能实时地将消息发送给消费者进行消费。但是,在消费者的处理消息的能力较弱的时候(比如,消费者端......
  • C 语言编写的简单词法分析器 reference.c
    #include<stdio.h>#include<string.h>#defineMAX500 #ifdef__unix#definefopen_s(pFile,filename,mode)((*(pFile))=fopen((filename),(mode)))==NULL#endifintmain(){ FILE*in,*out; charword[MAX];  charcp;  inti; if((fopen_s(&in,"......
  • 聊聊怎样快速去阅读JDK源码?
    1.前言之前断断续续读过一部分JDK常用类的源码,这里想把过程中的一些心得和方法记录下来,如果能帮到需要的小伙伴就再好不过了!本文主要分享一下我的阅读工具和阅读顺序。PS:由于当前主流使用的JDK版本仍是1.8,因此源码阅读主要是1.8版本,有些地方可以参考1.7。2.工具......
  • spring容器加载完毕做一件事情(利用ContextRefreshedEvent事件)
    关键字:spring容器加载完毕做一件事情(利用ContextRefreshedEvent事件)应用场景:很多时候我们想要在某个类加载完毕时干某件事情,但是使用了spring管理对象,我们这个类引用了其他类(可能是更复杂的关联),所以当我们去使用这个类做事情时发现包空指针错误,这是因为我们......
  • [HiBench] 安装HiBench,测试在Spark上跑PageRank与修改源码测试
    [HiBench]安装HiBench,测试在Spark上跑PageRank与修改源码测试背景:我想在HiBench上测试在Spark上跑PageRank性能,并想要修改PageRank的源码进行测试。本来,HiBench在README里写的已经挺清楚的了,直接照着做就行。奈何我用的服务器没有珂学上网,所以还是遇到了一点小麻烦。下载HiBe......
  • 番外篇:分享一道用Python基础+蒙特卡洛算法实现排列组合的题目(附源码)
    今日鸡汤夕阳无限好,只是近黄昏。    大家好,我是Python进阶者。    是不是觉得很诧异?明明上周刚发布了这篇:分享一道用Python基础+蒙特卡洛算法实现排列组合的题目(附源码),今天又来一篇,名曰番外篇!其实今天是想给大家分享【......
  • 分享一道用Python基础+蒙特卡洛算法实现排列组合的题目(附源码)
    今日鸡汤沙场烽火连胡月,海畔云山拥蓟城。    大家好,我是Python进阶者。这篇文章的题目真的是很难取,索性先取这个了,装个13好了。前言    前几天在才哥交流群里,有个叫【RickXiang】的粉丝在Python交流群里问了一道关于排列组合的问题,初步一看觉得很简单,实际上确实是有难度的......