Vue3 浅层响应式 API
1. ref vs shallowRef
1.1 基本概念
- ref: 深层响应式,会递归地将对象的所有属性转换为响应式
- shallowRef: 浅层响应式,只有 .value 的改变会触发更新,不会递归转换对象的属性
1.2 使用对比
const deepRef = ref({count: 0,nested: {value: 'hello'}
})
deepRef.value.count++
deepRef.value.nested.value = 'world'
const shallowValue = shallowRef({count: 0,nested: {value: 'hello'}
})
shallowValue.value.count++
shallowValue.value.nested.value = 'world'
shallowValue.value = { count: 1 }
1.3 性能优化示例
<template><div><video ref="videoRef" :src="videoUrl"></video><button @click="updateVideoUrl">更新视频</button></div>
</template><script setup>
import { shallowRef } from 'vue'// 使用 shallowRef 优化大型数据或 DOM 引用
const videoRef = shallowRef(null)
const videoUrl = shallowRef('https://example.com/video.mp4')const updateVideoUrl = () => {// 直接更新 .value 触发更新videoUrl.value = 'https://example.com/new-video.mp4'
}
</script>
2. reactive vs shallowReactive
2.1 基本概念
- reactive: 深层响应式,递归地将所有嵌套对象转换为响应式
- shallowReactive: 浅层响应式,只将对象的第一层属性转换为响应式
2.2 使用对比
const deepState = reactive({count: 0,nested: {value: 'hello'}
})
deepState.count++
deepState.nested.value = 'world'
const shallowState = shallowReactive({count: 0,nested: {value: 'hello'}
})
shallowState.count++
shallowState.nested.value = 'world'
shallowState.nested = { value: 'world' }
2.3 实际应用示例
<template><div><h2>用户信息</h2><div>姓名: {{ userInfo.name }}</div><div>年龄: {{ userInfo.age }}</div><!-- 不需要追踪 metadata 的变化 --><div>元数据: {{ userInfo.metadata.lastUpdated }}</div></div>
</template><script setup>
import { shallowReactive } from 'vue'// 使用 shallowReactive 优化性能,metadata 的变化不需要触发更新
const userInfo = shallowReactive({name: 'John',age: 30,metadata: {lastUpdated: new Date(),visits: 0}
})// 只有顶层属性的变化会触发更新
const updateUser = () => {userInfo.name = 'Jane' // 触发更新userInfo.metadata.visits++ // 不会触发更新
}
</script>
3. 使用场景对比
3.1 适合使用深层响应式(ref/reactive)的场景
- 表单数据
const formData = reactive({user: {name: '',email: '',preferences: {newsletter: true,notifications: {email: true,sms: false}}}
})
- 需要监听所有层级变化的数据
const settings = ref({theme: {dark: false,colors: {primary: '#000',secondary: '#fff'}}
})
3.2 适合使用浅层响应式(shallowRef/shallowReactive)的场景
- 大型数据结构且只需要监听顶层变化
const bigData = shallowRef({items: new Array(10000).fill(0).map((_, i) => ({id: i,data: { }}))
})
const updateData = () => {bigData.value = newBigData
}
- 外部库或 DOM 引用
const chartInstance = shallowRef(null)
const mapInstance = shallowRef(null)onMounted(() => {chartInstance.value = new ThirdPartyChart()mapInstance.value = new ThirdPartyMap()
})
- 不需要深层响应式的状态管理
const state = shallowReactive({ui: {loading: false,error: null},cache: new Map(), helpers: {formatter: () => {}, }
})
4. 性能优化建议
- 选择合适的响应式 API
const bigData = shallowRef(largeDataSet)
const bigData = ref(largeDataSet)
- 避免不必要的响应式转换
const config = shallowReactive({constants: { },settings: { }
})
const config = reactive({constants: { },settings: { }
})
- 合理组合使用
const state = reactive({userSettings: {theme: 'dark',notifications: { }},bigData: shallowRef(largeDataSet)
})
5. 注意事项
- 响应式丢失问题
const shallow = shallowReactive({nested: {count: 0}
})
const { nested } = shallow
nested.count++
- 替换整个对象
const data = shallowRef({nested: {value: 0}
})
data.value = {nested: {value: 1}
}
- 与计算属性配合
const data = shallowReactive({items: [],metadata: { }
})
const computedValue = computed(() => {return processItems(data.items)
})