Vue 3 的 Composition API 不仅仅是一种新的 API 风格,它代表了一种全新的代码组织思维——从"按选项类型组织"转向"按逻辑关注点组织"。本文将从一个真实项目的重构案例出发,深入讲解 Composition API 的实战技巧。
Options API 的痛点:逻辑碎片化
考虑一个典型的搜索组件,使用 Options API 编写时,一个功能(搜索)的逻辑会散落在 data、watch、methods、mounted、beforeUnmount 等多个选项中。当组件变得复杂时,在数百行代码中追踪一个功能的完整逻辑变得极其困难。
Composition API 的解决方案:按功能聚合
同样的搜索功能,用 Composition API 重写后,所有搜索相关的逻辑——状态、副作用、清理——都被封装在一个 composable 函数中。这就是 Composable(组合函数) 的核心思想。
function useSearch() {\n const keyword = ref('');\n const results = ref([]);\n const loading = ref(false);\n let timer = null;\n\n async function search() {\n loading.value = true;\n try { results.value = await fetchResults(keyword.value); }\n finally { loading.value = false; }\n }\n\n function debounceSearch(val) {\n clearTimeout(timer);\n timer = setTimeout(() => { if (val.trim()) search(); }, 300);\n }\n\n watch(keyword, debounceSearch);\n onBeforeUnmount(() => clearTimeout(timer));\n\n return { keyword, results, loading, search };\n}ref vs reactive:何时用哪个?
// ref:适用于基本类型和需要整体替换的场景\nconst count = ref(0);\nconst user = ref({ name: '张三' });\ncount.value++; // 需要 .value\nuser.value = { name: '李四' }; // 可以整体替换\n\n// reactive:适用于复杂对象,不需要 .value\nconst state = reactive({ user: { name: '张三' }, settings: { theme: 'dark' } });\nstate.user.name = '李四'; // 直接访问,无 .value\n\n// reactive 的限制:不能整体替换\nlet state = reactive({ count: 0 });\nstate = reactive({ count: 1 }); // 破坏了响应式引用\n// 用 ref 包装对象避免此问题实战建议:对于组件内部状态,优先使用 ref(更灵活,类型推断更好);对于包含多个相关属性的配置对象,使用 reactive。
Composable 设计原则
1. 单一职责
一个 Composable 只做一件事。如果 useUser() 既管理用户认证又管理用户偏好设置,应该拆分为 useAuth() 和 usePreferences()。
2. 可配置而非硬编码
function useSearch({ debounceMs = 300, minLength = 2 } = {}) { /* ... */ }3. 清理副作用
function useEventListener(target, event, handler) {\n onMounted(() => target.addEventListener(event, handler));\n onBeforeUnmount(() => target.removeEventListener(event, handler));\n}实战案例:可复用的数据获取 Composable
function useFetch(url) {\n const data = ref(null);\n const error = ref(null);\n const loading = ref(false);\n\n async function execute() {\n loading.value = true; error.value = null;\n try {\n const response = await fetch(url);\n if (!response.ok) throw new Error('请求失败');\n data.value = await response.json();\n } catch (e) { error.value = e.message; }\n finally { loading.value = false; }\n }\n\n if (isRef(url)) { watch(url, execute, { immediate: true }); }\n else { execute(); }\n\n return { data, error, loading, refetch: execute };\n}从 Options API 迁移的渐进策略
不需要一次性重写整个项目:新组件直接用 Composition API,提取可复用的 Composable 从现有 mixin 开始转化,复杂组件(超过 300 行)逐个重构,利用 setup 语法糖进一步简化代码。Options API 不会消失——对于简单组件,它仍然是非常好的选择。Composition API 的价值主要体现在复杂组件的逻辑组织和跨组件的逻辑复用。
评论 (0)