LOADING...

加载过慢请开启缓存(浏览器默认开启)

loading

Ref与reactive

2022/9/26 vue3

1. ref

ref 用于为数据添加响应式状态,可以让某一个变量具备响应式的能力。由于reactive只能传入对象类型的参数,而对于基本数据类型要添加响应式状态就只能用ref了,同样返回一个具有响应式状态的副本。

  • 在 js 中使用 ref 的值必须使用 .value 获取,在 Vue 的模板中使用 ref 的值不需要通过 value 获取
  • 语法:const xxx=ref(initValue),创建了一个包含响应式数据的引用对象
  • 接收的数据可以是:基本类型、对象类型,对于基本数据类型,ref是自己的实现方式且性能优于reactive;而对于对象类型,ref仍然是通过reactive包装实现的
  • 参数可以传递任意数据类型,传递对象类型时也能保持深度响应式,所以适用性更广。
  • vue 3.0 setup里定义数据时推荐优先使用ref,方便逻辑拆分和业务解耦。
import { ref } from "vue";

setup() {
    const msg = "张晓明";
    let age = ref(18);
    function add() {
      age.value += 1;
    }
    return { msg, age, add };
}

2. reactive

经过reactive函数处理后的对象能变成响应式的对象,类似于option api里面的data属性的值,它主要是处理你的对象让它经过 Proxy 的加工变为一个响应式的对象。

注意点:

  • 语法:const 代理对象=reactive(源对象),接收一个对象(或数组),返回一个代理对象(proxy对象)

  • 如果想要保持对象内容的响应式能力,在 return 的时候必须把整个 reactive() 对象返回出去

  • 在引用的时候也必须对整个对象进行引用而无法解构,否则这个对象内容的响应式能力将会丢失。

  • reactive()只能包装对象,基本类型不要用它,要用ref函数

  • reactive定义的响应式数据是深层次的,内部基于ES6的Proxy实现,通过代理对象操作源对象内部数据进行操作

<template>
  <div class="home">
    名字:{{ state.name }} 价格:{{ state.price }}
    购买数量:{{state.count}}
    <button @click="add">点我加1</button>
  </div>
</template>

<script>
import { ref, reactive } from "vue";

export default {
  name: "Home",
  components: {
  },
  setup() {
    //响应式对象
    const state = reactive({
      count: 0,
      name:"商品1",
      price:100
    });
    //修改响应式对象
    function add() {
      state.count += 1;
    }
    return { state, add };
  },
}
</script>

3. isRef & toRefs & toRef

a) isRef

用来判断某个值是否为ref创建出来的对象。

import { ref, isRef } from 'vue';
export default {
    setup () {
        const count = ref(1);
        const unwrappend = isRef(count) ? count.value : count;
 
        return {
           count,
           unwrappend
        };
    }
}

b) toRefs

但是在具体的业务中,如果无法使用解构取出 reactive() 对象的值,每次都需要通过 state. 操作符访问它里面的属性会是非常麻烦的,所以官方提供了 toRefs() 函数来为我们填好这个坑。只要使用 toRefs()reactive() 对象包装一下,就能够通过解构单独使用它里面的内容了。

toRefs 用于将响应式对象转换为结果对象,其中结果对象的每个属性都是指向原始对象相应属性的ref。

  • toRefs之后得到的ref引用在获取数据值的时候需要加.value
  • toRefs后的ref数据不是原始数据的拷贝,而是引用,改变结果数据的值也会同时改变原始数据
  • 作用其实和 toRef 类似,只不过 toRef 是一个个手动赋值,而 toRefs 是自动赋值。
<template>
  <div class="home">
    名字:{{ name }} 价格:{{ price }}
    购买数量:{{count}}
    <button @click="add">点我加1</button>
  </div>
</template>

<script>
import { ref, reactive,toRefs } from "vue";

export default {
  name: "Home",
  components: {
  },
  setup() {
    //响应式对象
    const state = reactive({
      count: 0,
      name:"商品1",
      price:100
    });
    //修改响应式对象
    function add() {
      //下面两种写法等效
      state.count += 1;
      // stateRefs.count.value+=1;
    }

    const stateRefs = toRefs(state)

    return { ...stateRefs, add };
  },
}
</script>

c) toRef

概念:为源响应式对象上的某个属性创建一个ref对象,二者内部操作的是同一个数据值,更新时二者是同步的。相当于浅拷贝一个属性。

  • toRef之后得到的ref属性在获取数据值的时候需要加.value
  • toRef后的ref数据不是原始数据的拷贝,而是引用,改变结果数据的值也会同时改变原始数据
<template>
  <div class="home">
    名字:{{ name }} 价格:{{ price }}
    购买数量:{{count}}
    <button @click="add">点我加1</button>
  </div>
</template>

<script>
import { ref, reactive,toRef } from "vue";

export default {
  name: "Home",
  components: {
  },
  setup() {
    //响应式对象
    const state = reactive({
      count: 0,
      name:"商品1",
      price:100
    });
    //修改响应式对象
    function add() {
      //下面两种写法等效
      //state.count += 1;
      count.value += 1;
    }

    const count = toRef(state, "count");

    return { count, add };
  },
}
</script>

d) ref reactive toRefs 和 toRef的比较

**ref : **原始数据没有变化,而ref“包裹的数据”变成了一个新的对象,而且模板有变化(相当于深拷贝)

**reactive : **reactive处理的数据无论是原始数据,“包裹后的数据”,还是模板,都有变化(代理模式)

toRef : toRef处理的数据会有变化,而原始数据也有变化,如果toRef处理是非响应式数据,此时模板没有变化 (相当于浅拷贝,引用关系)

toRefs : toRefs处理的数据响应变化,原始数据也响应变化,如果toRefs处理是非响应式数据,此时模板并没有变化(相当于浅拷贝,引用关系)

ref比较

备注:ref也可以用来定义对象或数组,但内部会自动通过reactive转为代理对象

img_show