下面来看看 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 一般用于 对象、数组 类型的数据,不需要用.value。
2、ref 一般用于 基础数据 类型的数据,在js中读取、修改时,需要.value,在模板中使用时不需要。
3、reactive 可以修改深层属性值,并保持响应。
4、reactive 返回值 和 源对象 不相等
5、reactive 的 属性值 可以是 ref 值
6、ref 本质也是 reactive, ref(obj) 等价于 reactive({ value: obj })
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 10 天 点击查看活动详情