Pinia 工程化实践:组织、持久化与服务端渲染
Pinia 工程化实践:组织、持久化与服务端渲染
store 的组织方式
按业务领域拆分而不是按技术类型:
stores/
user.ts # 登录态、权限、资料
posts.ts # 文章列表、筛选状态
comments.ts
ui.ts # 全局 UI:侧边栏开合、主题、通知
原则依然是:组件私有状态别放 store;只有跨路由、跨组件共享的才进。每个 store 保持单一职责,过大就按子领域再拆,store 之间可以互相调用,但要避免循环依赖。
组合式 store 的复用
通用逻辑抽成独立函数,store 里组合——和组件抽 composable 完全一样:
// composables/useAsyncResource.ts
export function useAsyncResource<T>(fetcher: () => Promise<T>) {
const data = ref<T>()
const loading = ref(false)
async function load() {
loading.value = true
data.value = await fetcher()
loading.value = false
}
return { data, loading, load }
}
// stores/posts.ts
export const usePostsStore = defineStore('posts', () => {
const { data: list, loading, load } = useAsyncResource(() =>
fetch('/api/posts').then(r => r.json())
)
const count = computed(() => list.value?.length ?? 0)
return { list, loading, count, load }
})
状态持久化
刷新页面 Pinia 状态会重置。用户偏好(主题、侧边栏)可直接用 VueUse:
import { useStorage } from '@vueuse/core'
const theme = useStorage('theme', 'light') // 自动同步 localStorage
通用方案用 pinia-plugin-persistedstate,在 store 上声明 persist,自动按 key 存取,还能选择只持久化部分字段。不要持久化敏感数据(token 应走 httpOnly Cookie)。
跨组件/路由的共享动作
// 组件外(如路由守卫、fetch 拦截器)使用 store,必须等 pinia 安装后
router.beforeEach(async () => {
const user = useUserStore()
if (!user.checked) await user.fetchMe()
})
SSR 注意点
- store 必须在每个请求内创建新实例(Nuxt 已自动处理),否则用户间状态串号
- 服务端填充的数据要在客户端激活前就位,Nuxt 里 useState/useFetch 自动序列化
- 避免在 store 初始化时直接访问 window/document
调试
DevTools 支持时间旅行、store 热更新;$onAction 可统一做埋点和日志。配合 TS,整个 store 的状态流几乎是自文档化的。
看到这里了?如果这篇文章帮到过你
请我喝瓶可乐就好 🥤

评论0 条
还没有评论,来抢沙发~