vue3 ref 和 reactive 的用法和区别

330 阅读3分钟

下面来看看 ref 和 reactive 的 用法 和 区别

vue3中,想让数据在页面中响应式地进行更新, 一般会用到 ref() 和 reactive() 这两个函数。

ref: 允许我们创建一个任意类型的响应式的ref对象, 在使用时需要带上.value

const a = ref(1)
a.value++
console.log(a.value) // 2


const b = ref({ count: 1 })
b.value.count++
console.log(b.value.count) // 2

在模板中, 使用ref对象时,

假如ref位于顶层,

那么久不需要使用 value, (也就是说,它会自动解包)。

如果ref对象是作为属性声明对象中,那么模板中进行运算时,仍然要使用.value


<script setup>
    import { ref } from 'vue'
    
    const a = ref(1)
    
    const b = { count: ref(2) }
    
    console.log(a.value) // 1
    
    console.log(b.count.vaue) // 2
    
</script>


<template>
    
    <h1> {{ a }} </h1> // 页面显示1, 自动解包
    
    <h1> {{ b.count }} </h1> // 页面显示2,作为插值自动解包
    
    <h1> {{ b.count + 1 }} </h1> // 页面显示[object Object]1
    <h1> {{ b.count.value + 1 }} </h1> // 正确写法,页面显示3
    
    <h1> {{ a + 1}} </h1> // 页面显示2 最顶层的ref不用写.value
    
</template>

所以,直接在页面使用b.count计算是无法正确显示的, 因为b.count本身就是一个ref对象, 并不位于顶层,所以没有自动解包


reactive:通常使用reactive() 来创建 一个 响应式的 对象或者数组,这样的对象或者数组状态都是默认深层响应式的

import { reactive } from 'vue'

const a = reactive( {
    count: 1
} )

a.count++

console.log(a.count) // 2


const b = reactive( {
    obj: {
        arr: ['Apple', 'Pear', 'Orange']
    }
} )

b.obj.arr.push('Strawberry')

console.log(b.obj.arr) // ['Apple', 'Pear', 'Orange', 'Strawberry']

不管有多深,都可以被追踪得到

reactive 局限性 :

1、仅仅对 对象类型有效(对象、数组、和 Map、Set这样的 结合类型),而对 string、number 和 boolean 这样的原始类型无效

2、因为 vue 的响应式 系统 是通过 属性访问 进行追踪的, 所以呢, 必须始终保持对 该响应式 对象的相同引用。

意味着我们不可以随意地 “替换” 一个响应式对象,因为这将导致对初始引用的响应性链接丢失。

let state = reactive({ count: 0 })

state = reactive({ count: 2 }) // 上面的引用 ({ count: 0 }) 将不再被追踪 (响应性连接已经丢失!)

a.count++

console.log(a.count) // 这时候就等于3 而不是等于2

同时也意味着当我们将 1、 响应式对象的属性赋值 或者 2、响应式 解构至本地变量 或者 3、将该属性传入一个函数时。将会失去响应性


1、响应式对象的属性赋值

const state = reactive({ count: 0 })

let n = state.count // 响应式对象的属性赋值

n++ // 这里+1 不会影响原始的 state

console.log(state.count) // 0

console.log(n) // 1

// n  state 互不影响

---

2、响应式 解构 到本地变量

let { count } = state

count++ // 这里不影响state的count

console.log(count) // 1 
console.log(state.count) // 0 这里还是0


---

3、将该属性传入一个函数

const myFunction = (count) => {
    count++
    count++
    
    return count
}

myFunction(state.count)

console.log(state.count) // 还是0 因为将该属性传入一个函数时。将会失去响应性

---

reactive 返回值 和 源对象 不相等

reactive 返回值是 一个 proxy 对象

let obj = { name: '张三' }

let reactiveObj = reactive(obj)


console.log(obj) // { name: '张三' }

console.log(reactiveObj) // Proxy { name: '张三' }

console.log(obj === reactiveObj) // false


reactive 的 值 可以是 ref 的 值

let name = ref('张三')

let nameReactive = reactive( { name } )

console.log( name.value === nameReactive.name ) // true


name.value = '李四'

console.log(name.value) // 李四

console.log(nameReactive.name) // 李四

nameReactive.name  = '张三'

console.log(name.value) // 张三

console.log(nameReactive.name) // 张三

ref 本质 就是 reactive

ref(obj) 等价于 reactive( { value: obj } )

let name = ref('张三')

let nameReactive = reactive({})

nameReactive.name  = name

console.log(name.value) // 张三

console.log(nameReactive.name) // 张三

console.log(name.value === nameReactive.name) // true


总结:

1、reactive 一般用于 对象、数组 类型的数据,不需要用.value2ref 一般用于 基础数据 类型的数据,在js中读取、修改时,需要.value,在模板中使用时不需要。

3、reactive 可以修改深层属性值,并保持响应。

4、reactive 返回值 和 源对象 不相等

5、reactive 的 属性值 可以是 ref6ref 本质也是 reactive, ref(obj) 等价于 reactive({ value: obj })

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 10 天 点击查看活动详情