手撕Vue源码之——ref

前言

上一篇文章给大家介绍了reactive的原理及实现一个简单的reactive(手撕Vue源码之------reactive),这篇文章就给大家介绍一下refref也是实现响应式的一种方法,但是它一般用于让原始类型的数据变成响应式,当然也可以是引用类型,但是一般不用,至于为什么之后会给大家说明的

思路

从vue打造好的ref来看,它接收一个参数,可以是简单类型也可以是引用类型,然后返回的是一个对象,从获取值需要使用.value就可以看出来,ref返回的结果是一个对象。

js 复制代码
import { track, trigger } from './effect.js'
import { reactive } from './reactive.js'


export function ref(val) {      // 将原始类型数据变成响应式  引用类型也可以
    return createRef(val)
}

function createRef(val) {
    // 判断val是否已经是响应式
    if (val.__v_isRef) {
        return val
    }
    
    // 将val变为响应式
    return new RefIpml(val)
}

class RefIpml {
    constructor(val) {
        this.__v_isRef = true    // 给每一个被ref操作过的属性值都添加标记
        this._value = convert(val)       // 一种人为约定俗成的写法,加了_的属性都默认为私有属性,不会直接拿到外面去用
    }
    get value() {
        // 为this对象做依赖收集
        track(this, 'value')    // key可以随便写,就统一用value,track和trigger里的key要统一
        return this._value
    }
    set value(newVal) {
        if (newVal !== this._value) {
            this._value = convert(newVal)
            trigger(this, 'value')      // 触发掉'value'上的所有副作用函数
        }
    }
}

function convert(val) {
    if (typeof val !== 'object' || val === null) {      // 不是对象
        return val
    } else {
        return reactive(val)
    }
}

因为Proxy只接受对象作为参数,而ref可以把简单数据类型变成响应式,所以我们就自己打造一个RefIpml类,这里先补充一个知识点,js中的对象天生拥有getset的能力。

js 复制代码
let obj = {
    name: 'Tom',
    get age() {
        return 18
    },
    set age(newVal) {
        console.log(newVal);
    }
}

obj.age = 18
console.log(obj.age);    // 相当于obj.age()

在函数前面加上get就可以直接使用对象名.函数名获取函数的返回结果,同理set也是,这样就不用每次都要去调用这个函数进行触发。

这里面还用到了我们上次在reactive中使用到的track方法和trigger方法,既然是响应式,那么ref自然也需要进行依赖收集和触发,代码片段里都有注释,相信大家也能看的懂,接下来我就讲讲为什么ref一般不用于引用类型而常用于简单数据类型。

从上面的代码也能看到,当ref如果接受的是一个对象的话,它是直接调用了reactive方法,把reactive的结果返回了出来,实际上vue的源码里也是这么写的,当给ref的参数是对象时,相当于就是在ref里面调用reactive,然后使用reactive返回的结果作为.value的值,这看着就有一点点多此一举。

结语

实际上变成响应式的核心就是Proxy方法,但是Proxy只能接受对象作为参数,所以才不得已再多打造一个ref用来使简单数据类型也能变成响应式数据,所以一般数据源比较多的时候就用reactive,数据源比较少的时候就用ref

假如您也和我一样,在准备春招。欢迎加我微信shunwuyu,这里有几十位一心去大厂的友友可以相互鼓励,分享信息,模拟面试,共读源码,齐刷算法,手撕面经。来吧,友友们!

相关推荐
橙某人20 小时前
SSR页面上的按钮点不了?Nuxt 懒加载水合揭秘💧
前端·vue.js·nuxt.js
PursuitofHappiness20 小时前
2 tree-cli 的使用方法
前端
不做超级小白20 小时前
把图片压小,但不糊:reduceUrImgs项目关键点拆解
前端·开源·node.js
耀耀切克闹灬20 小时前
Eruda 移动端调试工具使用指南
前端
王二端茶倒水20 小时前
现在AI Agent 已经能够代替程序员的工作了,作为一个程序员的我该如何规划以后的职业,请认真思考后给我最靠谱可行的建议。
前端·后端·面试
CyrusCJA20 小时前
毛玻璃效果
前端·css·css3
光影少年20 小时前
Monorepo架构是什么,如何学习Monorepo架构?
前端·学习·架构·前端框架
yuandiv20 小时前
让 Playwright 测试管理更优雅的利器
前端
拉拉肥_King20 小时前
Ant Design Vue a-image 图片预览充满全屏?为啥?
前端
极客沐森21 小时前
分页查询超亿级别的数据表缓慢,如何进行优化?
面试