# Vue 3 Code Review Guide > Vue 3 Composition API 代码审查指南,覆盖响应性系统、Props/Emits、Watchers、Composables、Vue 3.5 新特性等核心主题。 ## 目录 - [响应性系统](#响应性系统) - [Props & Emits](#props--emits) - [Vue 3.5 新特性](#vue-35-新特性) - [Watchers](#watchers) - [模板最佳实践](#模板最佳实践) - [Composables](#composables) - [性能优化](#性能优化) - [Review Checklist](#review-checklist) --- ## 响应性系统 ### ref vs reactive 选择 ```vue ``` ### 解构 reactive 对象 ```vue ``` ### computed 副作用 ```vue ``` ### shallowRef 优化 ```vue ``` --- ## Props & Emits ### 直接修改 props ```vue ``` ### defineProps 类型声明 ```vue ``` ### defineEmits 类型安全 ```vue ``` --- ## Vue 3.5 新特性 ### Reactive Props Destructure (3.5+) ```vue ``` ### defineModel (3.4+) ```vue ``` ### useTemplateRef (3.5+) ```vue ``` ### useId (3.5+) ```vue ``` ### onWatcherCleanup (3.5+) ```vue ``` ### Deferred Teleport (3.5+) ```vue ``` --- ## Watchers ### watch vs watchEffect ```vue ``` ### watch 清理函数 ```vue ``` ### watch 选项 ```vue ``` ### 监听多个源 ```vue ``` --- ## 模板最佳实践 ### v-for 的 key ```vue ``` ### v-if 和 v-for 优先级 ```vue ``` ### 事件处理 ```vue ``` --- ## Composables ### Composable 设计原则 ```typescript // ✅ 好的 composable 设计 export function useCounter(initialValue = 0) { const count = ref(initialValue) const increment = () => count.value++ const decrement = () => count.value-- const reset = () => count.value = initialValue // 返回响应式引用和方法 return { count: readonly(count), // 只读防止外部修改 increment, decrement, reset } } // ❌ 不要返回 .value export function useBadCounter() { const count = ref(0) return { count: count.value // ❌ 丢失响应性! } } ``` ### Props 传递给 composable ```vue ``` ### 异步 Composable ```typescript // ✅ 异步 composable 模式 export function useFetch(url: MaybeRefOrGetter) { const data = ref(null) const error = ref(null) const loading = ref(false) const execute = async () => { loading.value = true error.value = null try { const response = await fetch(toValue(url)) if (!response.ok) { throw new Error(`HTTP ${response.status}`) } data.value = await response.json() } catch (e) { error.value = e as Error } finally { loading.value = false } } // 响应式 URL 时自动重新获取 watchEffect(() => { toValue(url) // 追踪依赖 execute() }) return { data: readonly(data), error: readonly(error), loading: readonly(loading), refetch: execute } } // 使用 const { data, loading, error, refetch } = useFetch('/api/users') ``` ### 生命周期与清理 ```typescript // ✅ Composable 中正确处理生命周期 export function useEventListener( target: MaybeRefOrGetter, event: string, handler: EventListener ) { // 组件挂载后添加 onMounted(() => { toValue(target).addEventListener(event, handler) }) // 组件卸载时移除 onUnmounted(() => { toValue(target).removeEventListener(event, handler) }) } // ✅ 使用 effectScope 管理副作用 export function useFeature() { const scope = effectScope() scope.run(() => { // 所有响应式效果都在这个 scope 内 const state = ref(0) watch(state, () => { /* ... */ }) watchEffect(() => { /* ... */ }) }) // 清理所有效果 onUnmounted(() => scope.stop()) return { /* ... */ } } ``` --- ## 性能优化 ### v-memo ```vue ``` ### defineAsyncComponent ```vue ``` ### KeepAlive ```vue ``` ### 虚拟列表 ```vue ``` --- ## Review Checklist ### 响应性系统 - [ ] ref 用于基本类型,reactive 用于对象(或统一用 ref) - [ ] 没有解构 reactive 对象(或使用了 toRefs) - [ ] props 传递给 composable 时保持了响应性 - [ ] shallowRef/shallowReactive 用于大型对象优化 - [ ] computed 中没有副作用 ### Props & Emits - [ ] defineProps 使用 TypeScript 类型声明 - [ ] 复杂默认值使用 withDefaults + 工厂函数 - [ ] defineEmits 有完整的类型定义 - [ ] 没有直接修改 props - [ ] 考虑使用 defineModel 简化 v-model(Vue 3.4+) ### Vue 3.5 新特性(如适用) - [ ] 使用 Reactive Props Destructure 简化 props 访问 - [ ] 使用 useTemplateRef 替代 ref 属性 - [ ] 表单使用 useId 生成 SSR 安全的 ID - [ ] 使用 onWatcherCleanup 处理复杂清理逻辑 ### Watchers - [ ] watch/watchEffect 有适当的清理函数 - [ ] 异步 watch 处理了竞态条件 - [ ] flush: 'post' 用于 DOM 操作的 watcher - [ ] 避免过度使用 watcher(优先用 computed) - [ ] 考虑 once: true 用于一次性监听 ### 模板 - [ ] v-for 使用唯一且稳定的 key - [ ] v-if 和 v-for 没有在同一元素上 - [ ] 事件处理使用方法而非内联复杂逻辑 - [ ] 大型列表使用虚拟滚动 ### Composables - [ ] 相关逻辑提取到 composables - [ ] composables 返回响应式引用(不是 .value) - [ ] 纯函数不要包装成 composable - [ ] 副作用在组件卸载时清理 - [ ] 使用 effectScope 管理复杂副作用 ### 性能 - [ ] 大型组件拆分为小组件 - [ ] 使用 defineAsyncComponent 懒加载 - [ ] 避免不必要的响应式转换 - [ ] v-memo 用于昂贵的列表渲染 - [ ] KeepAlive 用于缓存动态组件