资讯专栏INFORMATION COLUMN

Vue3中reactive与ref函数使用场景

3403771864 / 295人阅读

  我们知道在 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 对象仅有一个.valueproperty,指向该内部值。 这是常规写法。

  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);

1.jpg

  上图显而易见,让对 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);

2.jpg

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

  结论是:没有

  总结来说就是ref 在 reactive 上在进行了封装进行了增强,因此在 Vue3 中 reactive 能做的,ref 也能做,reactive 不能做的,ref 也能做。希望大家以后多多交流,学习到更多。


文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/128010.html

相关文章

  • 剖析Vue3侦听器watch的使用教程

      上一节我们简单的介绍了一下vue3 项目中的计算属性,这一节我们继续 vue3 的基础知识讲解。  这一节我们来说 vue3 的侦听器。  学过 vue2 的小伙伴们肯定学习过侦听器,主要是用来监听页面数据或者是路由的变化,来执行相应的操作,在 vue3里面呢,也有侦听器的用法,功能基本一样,换汤不换药的东西。 侦听器是常用的 Vue API 之一,它用于监听一个数据并在数据变动时做一些自定义...

    3403771864 评论0 收藏0
  • Composition Api封装业务hook思路示例分享

      在近期的工作中有些知识总结分享就是使用 uniapp 的 Vue3 版进行开发。这样可以在开发中遇到业务场景相同的,就分装了一个hook 来减少代码,易于维护。  hook的场景  上图中已经很详细为我们展示3处使用到了获取列表的功能。分别是: 我的收藏、已投递岗位、未投递岗位。现在我们就来详细说说。  假如: 我的收藏、已投递岗位、未投递岗位 都各自获取列表,就会出现重复性的定义以下代码  ...

    3403771864 评论0 收藏0
  • vue3.0实践之写tsx语法实例

      00:先下载  yarn add @vitejs/plugin-vue-jsx -D  01:引入  vite.config.ts  import{defineConfig}from'vite'   importvuefrom'@vitejs/plugin-vue'   importvueJsxfrom'@vitejs/plugin-vue-jsx...

    3403771864 评论0 收藏0

发表评论

0条评论

3403771864

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<