Vue3 只读 API
1. readonly vs shallowReadonly
1.1 基本概念
- readonly: 深层只读,递归地将对象的所有属性设置为只读
- shallowReadonly: 浅层只读,只将对象的第一层属性设置为只读
1.2 使用对比
const original = reactive({
count: 0,
nested: {
value: 'hello'
}
})
const copy = readonly(original)
copy.count++
copy.nested.value = 'world'
const shallowCopy = shallowReadonly({
count: 0,
nested: {
value: 'hello'
}
})
shallowCopy.count++
shallowCopy.nested.value = 'world'
2. 实际应用场景
2.1 使用 readonly 的场景
- Props 保护
<script setup>
import { readonly } from 'vue'
const props = defineProps(['settings'])
// 确保组件不会修改 props
const safeProps = readonly(props)
// 使用 safeProps 代替直接使用 props
</script>
- 共享状态保护
import { reactive, readonly } from 'vue'
const state = reactive({
user: {
name: 'John',
preferences: {
theme: 'dark',
notifications: true
}
}
})
export const useStore = () => ({
state: readonly(state),
updateTheme: (theme) => {
state.user.preferences.theme = theme
}
})
2.2 使用 shallowReadonly 的场景
- 部分属性保护
const config = shallowReadonly({
api: {
endpoint: 'https://api.example.com',
timeout: 5000
},
settings: {
cache: true,
debug: false
}
})
config.api = {}
config.settings.cache = false
- 性能优化
const largeConfig = shallowReadonly({
constants: {
},
runtime: {
cache: new Map(),
temp: {}
}
})
3. 组件通信中的应用
3.1 父子组件通信
<!-- 父组件 -->
<script setup>
import { reactive, readonly } from 'vue'
const state = reactive({
user: {
name: 'John',
settings: {
theme: 'dark'
}
}
})
// 传递给子组件的只读版本
const readonlyState = readonly(state)
</script>
<template>
<child-component :state="readonlyState" />
</template>
<!-- 子组件 -->
<script setup>
const props = defineProps(['state'])
// 尝试修改会产生警告
const updateTheme = () => {
props.state.user.settings.theme = 'light' // 警告
}
</script>
3.2 状态管理
import { reactive, readonly, shallowReadonly } from 'vue'
const state = reactive({
user: {
profile: {
name: '',
email: ''
},
preferences: {
theme: 'light',
notifications: true
}
},
cache: new Map()
})
export const store = {
state: readonly(state),
cache: shallowReadonly(state.cache),
updateProfile(profile) {
state.user.profile = profile
},
updatePreferences(preferences) {
Object.assign(state.user.preferences, preferences)
}
}
4. 最佳实践
- 选择合适的只读级别
const sensitiveData = readonly(userData)
const config = shallowReadonly({
api: { },
cache: { }
})
- 组合使用
const store = {
state: readonly(coreState),
config: shallowReadonly(config),
cache: reactive(cacheData)
}
- 与 TypeScript 配合
interface State {
readonly user: {
readonly name: string;
readonly settings: {
readonly theme: string;
};
};
cache: Map<string, any>;
}
const state: State = shallowReadonly({
user: {
name: 'John',
settings: {
theme: 'dark'
}
},
cache: new Map()
})
5. 注意事项
- 响应式转换
const original = reactive({ count: 0 })
const copy = readonly(original)
original.count++
- 集合类型处理
const original = reactive(new Map())
const readonlyMap = readonly(original)
readonlyMap.set('key', 'value')
- 嵌套对象
const nested = shallowReadonly({
first: {
second: {
value: 1
}
}
})
nested.first = {}
nested.first.second.value = 2
- 与 ref 配合使用
const count = ref(0)
const readonlyCount = readonly(count)
count.value++
readonlyCount.value++