Vue3 ref toRef 和 toRefs

1,686 阅读2分钟

ref

基本用法

  1. 生成值类型的响应式数据
  2. 可用于模板和 reactive
  3. 通过.value修改值

示例代码

<template>
    <p>Ref Demo for {{state.name}} and {{ageRef}}</p>
    <p ref="elementRef">这是用来验证 ref template的</p>
</template>

<script>
import { ref, reactive, onMounted } from 'vue'

export default {
    name: 'Ref',
    setup() {
        const ageRef = ref(20) //值类型 响应式
        const nameRef = ref('Bean')

        const elementRef = ref(null)

        const state = reactive({     //可用于reactive
            name: nameRef
        })

        onMounted(() => {
            console.log("ref template is ===> ", elementRef.value)
        })

        setTimeout(() => {
            console.log("age is ===>" + ageRef.value)
            console.log("name is ===> " + state.name)

            ageRef.value = 30
            nameRef.value = 'Bean Mother'
        }, 1200);

        return { ageRef, state, elementRef }
    }    
}
</script>

vue3-ref.gif

toRef

基本用法

  1. 针对一个响应式对象(reactive)的prop
  2. 创建一个ref,具有响应式
  3. 两者保持引用关系

示例代码

<template>
    <p> toRef Demo for {{state.name}} -- {{ageRef}} --{{state.age}}</p>
</template>

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

export default {
    name: 'ToRef',
    setup() {
        const state = reactive({    //响应式对象,可以尝试把state设置成普通对象再实验,有什么效果?
            age: 20,
            name: 'Bean'
        })

        const ageRef = toRef(state, 'age')  //创建一个ref

        setTimeout(() => {    //ref和reactive保持引用关系,互相影响对方
            state.age = 30
        }, 1200);

        setTimeout(() => {
            ageRef.value = 40
        }, 2400);

        return {
            state, ageRef
        }
    }
}
</script>

vue3-toRef.gif

toRefs

基本用法

  1. 将响应式对象(reactive封装)转换成普通对象
  2. 对象的每个prop都是对应的ref
  3. 两者保持引用关系

示例代码

<template>
    <!-- <p> toRefs Demo for {{nameRef}} -- {{ageRef}}</p> -->
    <p> toRefs Demo for {{name}} -- {{age}}</p>
</template>

<script>
import { ref, toRef, toRefs, reactive } from 'vue'

export default {
    name: 'ToRefs',
    setup() {
        const state = reactive({    //响应式对象
            age: 20,
            name: 'Bean'
        })

        const stateToRefs = toRefs(state) //普通对象

        //用法一
        // const { age: ageRef, name: nameRef} = stateToRefs  //每个属性都是ref对象
        // return {
        //     ageRef, nameRef
        // }

        //用法二
        return stateToRefs
    }
}
</script>

vue3-toRefs.gif

ref toRef 和 toRefs的最佳使用方式

  1. 用reactive做对象的响应式,用ref做值类型的响应式
  2. setup中返回toRefs(state), 或者 toRef(state, '属性名')
  3. 合成函数返回响应式对象时,使用 toRefs

合成函数的示例代码

定义一个合成函数

function demo1() {
    const state = reactive({
        x: 25,
        y: 'Bean'
    })
    //逻辑运行状态,省略N行
    。。。。。。
    
    //返回时转换为ref
    return toRefs(state)

使用合成函数

export default {
    setup() {
        const {x, y} = demo1()
        
        return {
            x, y
        }
}

为啥需要用ref

在setup、computed、合成函数中,都有可能返回值类型。而值类型的返回,往往容易丢失响应式。

Vue3对响应式的处理方式有些改变,使用了Proxy。而这种方式对值类型的响应式却无能为力,所以在Vue3中只能通过ref这种方式来解决值类型响应式的问题。

那为啥ref需要.value?

  • ref是一个对象(不丢失响应式),value是存储值
  • 通过.value属性的get和set实现响应式
  • 只有ref用于模板、reactive时不需要.value,其他情况都需要

为啥需要 toRef 和 toRefs

  • 初衷: 在保证不丢失响应式的前提下,把对象解构,方便对象数据分解和扩散
  • 前提:针对的是响应式对象(reactive封装的)非普通对象
  • 注意: 不创造响应式(那是reactive的事情),只是延续响应式