共计 2203 个字符,预计需要花费 6 分钟才能阅读完成。
传统 Options API 的局限性
在 Vue2 时代,Options API 是我们管理组件状态的主要方式。但随着应用规模扩大,这种模式逐渐暴露出几个明显问题:

- 逻辑关注点分散:相关代码被强制拆分到 data、methods、computed 等不同选项中,一个完整功能需要跨多个区块查看
- 复用困难:mixins 虽然能实现逻辑复用,但存在命名冲突和来源不清晰的问题
- 类型支持弱:在 TypeScript 项目中难以获得完善的类型推导
- 全局状态管理笨重:Vuex 的模块系统配置繁琐,且与组件逻辑割裂
Composition API vs Pinia
Vue3 带来的 Composition API 和 Pinia 库为状态管理提供了新的思路:
- Composition API 优势
- 逻辑关注点集中:相关代码可以组织在一起
- 更好的类型支持:天然适合 TypeScript
- 灵活的组合能力:可以像函数一样封装和复用逻辑
-
更细粒度的响应式控制
-
Pinia 优势
- 专为 Vue3 设计的状态管理库
- 去除了 mutations,简化了概念
- 支持 Composition API 和 Options API 两种风格
- 内置 TypeScript 支持
-
模块化设计更直观
-
选择建议
- 组件内部状态:优先使用 Composition API
- 跨组件共享状态:考虑 Pinia
- 大型项目:可以组合使用
基于 Composition API 的状态管理实现
下面是一个使用 Composition API 管理复杂状态的示例:
import {ref, computed, watch} from 'vue'
interface UserState {
id: number
name: string
roles: string[]
preferences: {
theme: 'light' | 'dark'
notifications: boolean
}
}
export function useUserStore() {
// 响应式状态
const user = ref<UserState | null>(null)
const loading = ref(false)
const error = ref<string | null>(null)
// 计算属性
const isAdmin = computed(() => {return user.value?.roles.includes('admin') ?? false
})
// 方法
async function fetchUser(userId: number) {
loading.value = true
try {const response = await fetch(`/api/users/${userId}`)
user.value = await response.json()} catch (err) {error.value = err.message} finally {loading.value = false}
}
function updatePreference(key: keyof UserState['preferences'], value: any) {if (user.value) {user.value.preferences[key] = value
}
}
// 监听变化
watch(() => user.value?.preferences.theme,
(newTheme) => {document.documentElement.setAttribute('data-theme', newTheme)
}
)
return {
user,
loading,
error,
isAdmin,
fetchUser,
updatePreference
}
}
进阶话题
状态持久化
对于需要持久化的状态(如用户偏好),可以考虑以下方案:
-
使用 localStorage:
// 保存 watch(user, (newVal) => {localStorage.setItem('user', JSON.stringify(newVal)) }, {deep: true}) // 恢复 const savedUser = localStorage.getItem('user') if (savedUser) {user.value = JSON.parse(savedUser) } -
使用插件:如 vueuse 的 useStorage 或 pinia-plugin-persistedstate
服务端渲染 (SSR) 兼容性
在 SSR 场景下需要注意:
- 避免直接使用浏览器 API(如 localStorage)
- 使用 pinia 时确保每个请求都有独立的状态实例
- 考虑状态序列化和反序列化
性能优化与最佳实践
- 响应式优化
- 合理使用 shallowRef/shallowReactive 减少不必要的深层响应式
- 对大数组使用 markRaw 标记非响应式部分
-
避免在模板中使用复杂表达式
-
组织建议
- 按功能而非类型组织代码
- 为复杂状态定义清晰的接口类型
-
将相关操作封装在一起
-
调试技巧
- 使用 Vue DevTools 的 Timeline 功能
- 为重要状态变化添加调试日志
- 利用 watchEffect 进行依赖追踪
思考与探索
在上述方案中,我们混合使用了 ref 和 computed 来管理状态。但这种方式在跨组件共享时仍需要手动处理注入。思考以下问题:
- 如何设计一个既能享受 Composition API 灵活性,又能像 Pinia 那样方便共享的状态管理系统?
- 在微前端架构下,不同子应用间的状态共享有哪些可行方案?
- 如何平衡状态管理的集中化与组件自治的需求?
期待你在实践中找到自己的答案,并分享你的解决方案。
正文完
发表至: 前端开发
五天前
