响应式进阶
computed、watch 与渲染优化。
响应式进阶
这一课你将能做到
- 用
ref和reactive创建响应式数据,并知道何时用哪个 - 用
computed派生计算属性 - 用
watch和watchEffect监听数据变化 - 用
toRef/toRefs解构响应式对象不丢失响应性
为什么要学
响应式是 Vue 的「心脏」。你写的每一行 count.value++,背后都是 Vue 的依赖追踪和视图更新。不理解响应式,写出的代码要么不更新,要么更新过度。
人话:响应式就像「自动记账本」。你告诉 Vue「这个数据很重要」,之后每次数据变动,Vue 自动更新所有用到它的地方,不用你手动通知。
先建立图像
<script setup>
import { ref, computed, watch } from 'vue'
const count = ref(0)
const double = computed(() => count.value * 2)
watch(count, (newVal, oldVal) => {
console.log(`从 ${oldVal} 变成 ${newVal}`)
})
</script>
<template>
<p>原始:{{ count }}</p>
<p>双倍:{{ double }}</p>
<button @click="count++">+1</button>
</template>
跟着做
步骤 1:ref 包装基本类型
<script setup>
import { ref } from 'vue'
const num = ref(0)
const str = ref('hello')
const bool = ref(true)
function change() {
num.value = 100 // 正确:通过 .value 修改
str.value = 'world'
}
</script>
ref 适合包装数字、字符串、布尔值,也可以包装对象。
步骤 2:reactive 包装对象
<script setup>
import { reactive } from 'vue'
const user = reactive({
name: '张三',
age: 25,
address: { city: '北京' }
})
function update() {
user.age = 26 // 直接改属性,不用 .value
user.address.city = '上海' // 深层也响应式
}
</script>
reactive 只能包装对象/数组,不能包装基本类型。
步骤 3:computed 计算属性
<script setup>
import { ref, computed } from 'vue'
const price = ref(100)
const count = ref(2)
// 只读计算属性
const total = computed(() => price.value * count.value)
// 可写计算属性
const totalWritable = computed({
get: () => price.value * count.value,
set: (val) => { price.value = val / count.value }
})
</script>
computed 有缓存,依赖不变时不重复计算。
步骤 4:watch 监听变化
<script setup>
import { ref, watch } from 'vue'
const keyword = ref('')
// 监听单个 ref
watch(keyword, (newVal, oldVal) => {
console.log('搜索:', newVal)
})
// 监听多个源
watch([keyword, () => props.id], ([newKw, newId]) => {
fetchData(newKw, newId)
})
// 深度监听
const obj = ref({ a: 1 })
watch(obj, (val) => console.log(val), { deep: true })
</script>