Vue3中reactive与ref函数使用场景

 更新时间:2022年07月13日 09:18:31   作者:拜小白  
这篇文章主要为大家介绍了Vue3 中有场景是 reactive 能做而 ref 做不了的使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

前言

如果你使用过 Vue3,你知道的,在 Vue3 中有两个非常常用的响应式 API:reactive 和 ref。它们会把我们想要追踪的数据变成响应式。

而且我们在使用时一直被告知 ref 用于创建基础类型的响应式,也可以创建引用类型的响应式。而对于引用类型,底层也是转换为 reactive 来进行响应式处理。那既然这样为撒还需要 reactive ,全部使用 ref 不就行了吗?

虽然 ref 创建的响应式数据在脚本中需要通过 .value 才能访问到呀!但是这里肯定影响不大。并且在模板中会自动添加上 .value,所以模板中不需要通过 .value 访问。

既然这二者基本没撒差别,但是还是暴露了 reactive 这个 API,难道有什么场景是 reactive 能做而 ref 做不了的?

简单了解 ref & reactive

我们先简单了解一下这两个 API。

reactive

返回对象的响应式副本,响应式转换是“深层”的——它影响所有嵌套 property。我们一般这样写。

const obj = reactive({ count: 0 })

并且可以直接使用。

const count = obj.count

ref

接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象仅有一个 .value property,指向该内部值。 我们一般是这样写。

const data = ref(xxx)

引用的时候,一般会通过data.value的方式引用。

const dataValue = data.value

通过跟踪 Vue3 的源代码可以证明,当我们调用 ref 方法来定义响应式数据时,当参数为对象类型时,其实里面用的是 reactive 方法。也就是说上面的 data.value ,事实上是 reactive 方法创造出来的。

reactive 能做的 ref 也能做,并且还是用 reactive 做的

我们通过源码来看看 ref 的源码实现。

源码分析版本:3.2.36

function ref(value) {
    return createRef(value, false);
}

ref 函数跳转到 createRef 函数。

function createRef(rawValue, shallow) {
    ...
    return new RefImpl(rawValue, shallow);
}

createRef 函数返回的是 RefImpl 类的实例,换句话说,ref 创建出来的响应式就是 RefImpl 实例对象。

const count = ref(1);
console.log(count);

我们重点来看看这个 RefImpl 类。

class RefImpl {
    constructor(value, __v_isShallow) {
        ... 
        this._value = __v_isShallow ? value : toReactive(value);
    }
    get value() {
        trackRefValue(this);
        return this._value;
    }
    set value(newVal) {
        newVal = this.__v_isShallow ? newVal : toRaw(newVal);
        if (hasChanged(newVal, this._rawValue)) {
            this._rawValue = newVal;
            this._value = this.__v_isShallow ? newVal : toReactive(newVal);
            triggerRefValue(this, newVal);
        }
    }
}

__v_isShallow 参数在这里默认是 false,这里也顺带讲一嘴,当我们在使用 shallowRef 时,这个参数为 true。

function shallowRef(value) {
    return createRef(value, true);
}

Ref 与 Reactive 创建的都是递归响应的,将每一层的 json 数据解析成一个 proxy 对象,shallowRef 与 shallowReactive 创建的是非递归的响应对象,shallowReactive 创建的数据第一层数据改变会重新渲染 dom。

 var state = shallowReactive({
    a:'a',
    gf:{
       b:'b',
       f:{
          c:'c',
          s:{d:'d'}
       }
    }
 });
// 改变第一层的数据会导致页面重新渲染
state.a = '1'
// 如果不改变第一层,只改变其他的数据页面不会重新渲染 
state.gf.b = 2

通过 shallowRef 创建的响应式对象,需要修改整个 value 才能重新渲染 dom。

var state = shallowRef({
   a:'a',
    gf:{
       b:'b',
       f:{
          c:'c',
          s:{d:'d'}
       }
    }
});
// 不会重新渲染
state.value.a = 1
// 要修改整个 value 才能重新渲染
state.value = {
    a:'1',
    gf:{
       b:'2',
       f:{
          c:'3',
          s:{d:'d'}
       }
    }
}

如果想更新 shallowRef 的某一层数据,并且想触发渲染,可以使用 triggerRef。

var state = shallowRef({
   a:'a',
    gf:{
       b:'b',
       f:{
          c:'c',
          s:{d:'d'}
       }
    }
})
state.value.gf.f.s.d = 4
triggerRef(state)

所以这里会走到 toReactive(value) 函数。

const isObject = (val) => val !== null && typeof val === 'object';
const toReactive = (value) => isObject(value) ? reactive(value) : value;

可以看到,如果传入的参数是一个对象的话,返回值将会继续调用 reactive 方法来进行包裹,reactive 最终会通过 Proxy 来进行实现响应拦截,返回的也是一个 Proxy 对象,但在这里不重要,我们只需要知道当 ref 的参数为对象时,用的就是 reactive 方法。

const data = reactive({
  count: 1,
});
console.log(data);
const data_ref = ref({
  count: 1,
});
console.log(data_ref);

结果显然,让对 ref 传入对象作为参数时和传入基本类型作为参数返回结果情况是不一样的。

基本类型返回值value就是具体的值,对象类型返回值value是 reactive 方法创建的 proxy 对象。

通过源码来看,其实也证明了,在 Vue3 中,如果是把对象类型的数据弄成响应式,reactive 和 ref 都可以,且ref 内部是通过r eactive 来支持的。

也就是说,你 reactive 能做的,我 ref 也能做。

ref 能做,但是 reactive 不能做

其实通过上面的例子就能知道有什么是 reactive 不能做的呢?很明显,reactive 不支持对基本类型数据响应式,也就是说基本类型数据不能直接作为 reactive 的参数来使用。

简单看看源码。

function reactive(target) {
    ...
    return createReactiveObject(...);
}

reactive 函数跳转到 createReactiveObject 函数。

const isObject = (val) => val !== null && typeof val === 'object';
function createReactiveObject(...) {
    if (!isObject(target)) {
        {
            console.warn(`value cannot be made reactive: ${String(target)}`);
        }
        return target;
    }
    ...
    const proxy = new Proxy(...);
    proxyMap.set(target, proxy);
    return proxy;
}

createReactiveObject 一开始就会判断 target 是否是对象,如果不是对象就会直接⚠️提示返回。如果是对象就会把 target 用 Proxy 变成响应式对象。

const data = reactive(10);

总结

我们通过源码来分析了两个响应式 API,发现 Vue3 中有没有 reactive 能做而 ref 做不了的场景?

结论是:没有

简单来说 ref 是在 reactive 上在进行了封装进行了增强,所以在 Vue3 中 reactive 能做的,ref 也能做,reactive 不能做的,ref 也能做。

参考

https://v3.cn.vuejs.org/api/refs-api.html#ref

https://v3.cn.vuejs.org/api/basic-reactivity.html

https://v3.cn.vuejs.org/guide/reactivity.html#什么是响应性

https://github.com/vuejs/docs-next-zh-c

以上就是Vue3中reactive与ref函数使用场景的详细内容,更多关于Vue3 reactive ref函数的资料请关注脚本之家其它相关文章!

相关文章

  • Vue使用babel-polyfill兼容IE解决白屏及语法报错问题

    Vue使用babel-polyfill兼容IE解决白屏及语法报错问题

    这篇文章主要介绍了Vue使用babel-polyfill兼容IE解决白屏及语法报错问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • vue 界面刷新数据被清除 localStorage的使用详解

    vue 界面刷新数据被清除 localStorage的使用详解

    今天小编就为大家分享一篇vue 界面刷新数据被清除 localStorage的使用详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • vue面试之new Vue的时候到底做了什么

    vue面试之new Vue的时候到底做了什么

    这篇文章主要介绍了vue面试之new Vue的时候到底做了什么原理及vue加载流程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • Vue项目中使用jquery的简单方法

    Vue项目中使用jquery的简单方法

    这篇文章主要给大家介绍了关于Vue项目中使用jquery的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Vue具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-05-05
  • vue.js template模板的使用(仿饿了么布局)

    vue.js template模板的使用(仿饿了么布局)

    这篇文章主要介绍了vue.js template模板的使用,主要是模仿饿了么布局,用到了4个组件,分别是header.vue,goods.vue,ratings.vue,seller.vue,感兴趣的朋友跟随脚本之家小编一起看看实现代码
    2018-08-08
  • 如何快速上手Vuex

    如何快速上手Vuex

    本文主要介绍了Javascript中Vuex的相关知识。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • vue3锚点定位多种方法详解

    vue3锚点定位多种方法详解

    这篇文章主要介绍了vue3的锚点定位多种方法,需要的朋友可以参考下
    2024-01-01
  • vue路由跳转传参数的方法

    vue路由跳转传参数的方法

    这篇文章主要介绍了vue路由跳转传参数的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-05-05
  • 关于Vue中过滤器的必懂小知识

    关于Vue中过滤器的必懂小知识

    vue过滤器可以在不改变原始数据,只是对数据进行加工处理后返回过滤后的数据再进行调用处理,下面这篇文章主要给大家介绍了关于Vue中过滤器必懂小知识的相关资料,需要的朋友可以参考下
    2021-10-10
  • Vue3中使用Monaco-editor的教程详解

    Vue3中使用Monaco-editor的教程详解

    Monaco-editor,一个vs code 编辑器,需要将其继承到项目,这篇文章主要为大家详细介绍了如何在vue中安装和使用Monaco-editor,有需要的小伙伴可以参考下
    2023-11-11

最新评论