目录
前言
Vue提供各种API对View视图进行操作,这里介绍ref和reactive响应式,以及他们的区别
ref()
- 组合式API中,推荐使用ref来声明响应式状态(模板变量)
- 当你再模板中使用了ref,并且改变了ref的值,Vue会自动检测值的变化并更新相应DOM。
- 组件在首次渲染时,Vue会跟踪在渲染过程中使用过的每一个ref。
- ref被修改时,会触发追踪它的组件的一次重新渲染
- 重点:.value赋值才会重新渲染模板DOM!
ref声明响应式变量案例
// setup是Vue3的一个特殊钩子函数,相当于语法糖,为组合式API提供便利
// 无需手动编写setup,以及相应的ref解包操作
<script setup>
import { ref } from 'vue'
const count = ref(0)
// 经过ref封装的变量会多出.value
// .value是一组get和set方法,用于Vue来检测ref访问和修改
console.log(count) // { value: 0 }
console.log(count.value) // 0
function increment() {
count.value++
}
</script>
<template>
<button @click="increment">
{{ count }}
</button>
</template>
ref深层响应特性
- ref声明的变量,即使是嵌套的对象值或者数组值改变,依然会检测响应更新到模板DOM。
- shallowRef()可以避免深层递归转为响应式
import { ref } from 'vue'
const obj = ref({
nested: { count: 0 },
arr: ['foo', 'bar']
})
function mutateDeeply() {
// 以下都会按照期望工作
obj.value.nested.count++
obj.value.arr.push('baz')
}
DOM更新时机(nextTick之后)
- 响应式状态修改时,DOM会自动更新。但DOM更新并非同步。
- Vue会在“next tick”更新周期中缓冲所有状态的修改,以确保不管修改了多少次响应式状态,组件只会更新一次。
- 如果您预期等待DOM更新完成后要执行一些操作,可以使用nextTick()全局API。
import { nextTick } from 'vue'
async function increment() {
count.value++
await nextTick()
// 现在 DOM 已经更新了
}
reactive()
- reactive在作用,以及使用上与ref()几乎一致。
- reactive返回的是一个原始对象的Proxy代理对象,该代理对象与原始对象并不相等。
- 只有代理对象是响应式,更改原始对象并不触发模板DOM更新。
- shallowReactive()可以退出深层响应。
- 一致性
- 对同一个原始对象调用reactive(),会返回同一个Proxy代理对象。
- 对已存在的Proxy代理对象调用reactive(),会返回其本身。
- 响应式对象内的嵌套对象依然是Proxy代理对象,该代理对象与原始对象并不相等
- reactive只能作用于对象类型数据(对象,数组,Map,Set),无法作用于基础数据类型。
- reactive不能轻易替换整个对象,这会导致第一个建立跟踪链接的对象失去响应性。
- reactive对解构操作并不友好,
- 更推荐使用ref
// 代码案例1
const raw = {}
const proxy = reactive(raw)
// 代理对象和原始对象不是全等的
console.log(proxy === raw) // false
// 代码案例2
// 响应式对象内的嵌套对象依然是Proxy代理对象
const proxy = reactive({})
const raw = {}
proxy.nested = raw
console.log(proxy.nested === raw) // false
// 代码案例3:解构时会丢失响应性变化
const state = reactive({ count: 0 })
// 当解构时,count 已经与 state.count 断开连接
let { count } = state
// 不会影响原始的 state
count++
// 该函数接收到的是一个普通的数字
// 并且无法追踪 state.count 的变化
// 我们必须传入整个对象以保持响应性
callSomeFunction(state.count)
ref与reactive区别
- ref
- ref仅适用基础数据类型(字符串,数字,布尔值等)和对象类型。
- ref在处理对象类型时,内部会自动调用reactive转换为响应式代理。
- ref底层基于reactive二次封装。
- ref必须通过.value访问或修改属性值(在模板DOM中会自动解构)。
- 底层
- 对基础数据类型使用getter/setter劫持,对对象类型通过reactive实现代理。
- 本质是包含value属性的封装对象,可以直接替换(ref.value = newObj)。
- reactive
- reactive仅支持对象类型(包括数组,Map,Set等),无法直接处理基础数据类型。
- reactive可直接访问属性(如state.count)。
- reactive通过Proxy实现深度响应式(基于ES6 Proxy实现深度响应式代理,递归追踪嵌套对象变化)。
- 无法整体替换原始对象,否则失去响应性。
1637

被折叠的 条评论
为什么被折叠?



