• Vue3 之 reactive ref toRef toRefs


    Vue3 之 reactive ref toRef toRefs

    reactive

    创建响应式的对象,只能传入对象,是创建一个该对象的Proxy,他就是原对象的一个响应式副本,不等于原始对象,它“深层”转换了源对象的所有嵌套 property,解包并维持其中的任何ref引用关系。
    reactive API很好地解决了 Vue2 通过 defineProperty 实现数据响应式时的缺陷。

    ref

    就也是创建响应式对象,但是任何数据类型都可以作为参数,将参数包裹成一个具有value 属性 的对象返回,然后使用ref对象.value访问或者更改数据,----因为基础数据类型只能传递值而不是引用地址,将它包装在一个对象内,可以实现数据的响应式。

    因为ref就是通过reactive包装了一个对象 ,然后将值传给该对象的value属性,这也就是为什么每次访问时我们都需要加上.value。可以简单地把 ref(obj) 理解为 reactive({ value: obj })

    如何选择 refreactive?建议:

    1. 基础类型值(StringNumberBoolean等) 或单值对象(类似{ count: 3 }这样只有一个属性值的对象) 使用 ref
    2. 引用类型值(ObjectArray)使用 reactive
    3. 对于 ref 对象可以使用 unref 语法糖来免去.value访问的困扰

    toRef(原对象,对象的属性名)

    传入对象的某一个属性创建一个响应式的ref, 它会保持对其源 property 的响应式连接。

    <template>
      <p>ref state1: {{ state1.count }}</p>
      <button @click="add1">增加 state1 的 count</button>
      <p>toRef state2: {{ state2 }}</p>
      <button @click="add2">增加 state2</button>
    </template>
    
    <script>
    import { ref, toRef } from 'vue'
    export default {
      setup() {
        const obj = { count: 3 }
        const state1 = ref(obj) 
        // const state1 = ref(obj.count) // 如果传简单数据类型是值传递,无法体现对源数据的响应式
        const state2 = toRef(obj, 'count')
        function add1() {
          state1.value.count ++
          console.log('原始值:', obj); // obj的 count 递增
          console.log('响应式数据对象:', state1.value.count); 
          console.log('state2', state2.value)
          // state1 的 count 属性 和 state 2 递增,页面上的 state1 和 state2 也递增
        }
        function add2() {
          state2.value ++
          console.log('原始值:', obj); // obj 的 count 递增
          console.log('响应式数据对象:', state2.value); 
          console.log('state1', state1.value.count)
          // state2 的值 和 state1 的 count 属性也同步递增,页面上的 state1 和 state2无变化
        }
    
        return { state1, state2, add1, add2 }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    得出结论:
    ref 创建一个响应式对象,如果传入参数是对象,那么与对象所有嵌套属性都维持数据响应。它的作用是 data 选项 般的存在,即组件内部状态ref值改变会触发页面渲染,同时能作为props或 事件参数 进行组件通信。
    toRef 是对传入对象指定属性的响应式绑定值改变不会更新视图。因此用它创建的变量不作用于模版渲染,而是用来接收诸如props引用式传递。举例来说:通常就是我们在模板中只想要渲染出obj里面的一个属性,如果直接返回该值,那么就会失去响应式,因此使用toRef既能只抛出一个属性且保持响应式。

    toRefs

    使用toRef过程中,会发现,toRef只能代理一个对象属性。使用toRef可以代理这个对象下的所有属性。
    了解完 toRef 后,就很好理解 toRefs 了,其作用是生成一个新对象,内部每个属性都指向传入的对象的相应 property 的响应式数据 ref
    也就是说,新对象本身与原对象的无关联(指向新的引用地址),但它的所有属性却都与源对象的对应属性建立了响应性。
    toRef 可以记成建立一个 ref 属性值的引用,toRefs 则是所有 ref 响应属性值的引用。

    如果直接对响应式数据解构,那么数据就会失去响应性,所以就需要toRefs建立响应式关联,一般都是根据key进行解构

    如果某个属性不存在,这种情况下toRefs不会为不存在的属性创建ref,此时就需要使用toRef

    总结

    • refreactive是在setup()声明组件内部状态用的, 这些变量通常都要 return 出去,除了供