Files
Pulse ae39e45460 feat: biblioteca inteligente libs/ + 5 novas skills (20 skills total)
NOVAS SKILLS:
- next-best-practices      v0.1.0  (CLEAN) — Next.js App Router, RSC, caching, data
- nextjs-patterns          v1.0.0  (CLEAN) — Next.js 15: Server Actions, route handlers
- vite                     v1.0.0  (CLEAN) — env vars, aliases, proxy, CJS compat
- uncle-bob                v1.0.0  (CLEAN) — Clean Code, SOLID, Clean Architecture
- clean-code-review        v1.0.0  (CLEAN) — naming, guard clauses, anti-patterns, refactoring
- vue                      v1.0.0  (CLEAN) — Vue framework
- vue-composition-api-best-practices v1.0.0 (CLEAN) — composables, Pinia, reactivity

BIBLIOTECA INTELIGENTE libs/ (10 dominios, 11 arquivos):
- typescript/ — TS safe + generics gotchas
- react/ — Next.js App Router + Vite config
- vue/ — Composition API + Pinia
- linux/ — System diagnostic cheatsheet
- database/ — PostgreSQL + MySQL patterns
- browser/ — Chromium CLI + E2E testing
- security/ — SAST audit (OWASP Top 10)
- best-practices/ — Clean Code + SOLID + Clean Architecture
- deploy/ — Docker multi-stack + OpenClaw ops
- + INDEX.md como guia de navegacao

.learnings/ — LRN-20260519-003 criado (biblioteca compartilhada)
2026-05-19 21:03:25 -03:00

4.9 KiB
Raw Permalink Blame History

Store Without 模式

问题

Pinia 的 useStore() 默认依赖 Vue 组件上下文(inject/provide)。在组件外(hooks、utils、plugins、路由守卫、axios 拦截器)直接调用会抛出错误:

Error: "getActivePinia()" was called but there was no active Pinia.

解决方案:Store Without 模式

每个 store 模块额外导出一个 useXxxStoreWithOut 函数,接收全局 pinia 实例作为参数,使 store 可在任意上下文中安全访问。

模式定义

// store/modules/app.ts
import { defineStore } from 'pinia'
import { store } from '@/store'

export const useAppStore = defineStore('app', {
  // ... store 定义
})

// 在组件外使用时,传入全局 pinia 实例
export const useAppStoreWithOut = () => {
  return useAppStore(store)
}

全局 Pinia 实例

// store/index.ts
import { createPinia } from 'pinia'

const pinia = createPinia()

export default pinia

// 导出 store 供 Without 函数使用
export const store = pinia

使用规则

何时使用哪个

函数 使用场景 原因
useAppStore() Vue 组件 <script setup> 自动从组件上下文获取 pinia
useAppStoreWithOut() hooks、utils、plugins、路由守卫等 组件上下文不可用,需显式传入 pinia

在 Vue 组件中(始终使用标准方式)

// ✅ GOOD:组件内使用标准方式
<script setup lang="ts">
import { useAppStore } from '@/store/modules/app'

const appStore = useAppStore()
</script>
// ❌ BAD:组件内使用 WithOut 是多余的
<script setup lang="ts">
import { useAppStoreWithOut } from '@/store/modules/app'

const appStore = useAppStoreWithOut() // 可以工作但不必要
</script>

在 Hooks / Utils / Plugins 中(必须使用 WithOut

// ✅ GOODhooks 中使用 WithOut
// hooks/web/useSideCategory.ts
import { useBusinessStoreWithOut } from '@/store/modules/business'

export function useSideCategory() {
  const businessStore = useBusinessStoreWithOut()
  const categories = computed(() => businessStore.getSideCategory)
  return { categories }
}
// ✅ GOODutils 中使用 WithOut
// utils/migration.ts
import { useBusinessStoreWithOut } from '@/store/modules/business'

export async function migrateOnlineIcons() {
  const businessStore = useBusinessStoreWithOut()
  // ...
}
// ❌ BAD:组件外直接使用标准方式会报错
// utils/migration.ts
import { useBusinessStore } from '@/store/modules/business'

export async function migrateOnlineIcons() {
  const businessStore = useBusinessStore() // Error: no active Pinia
}

命名规范

所有模块遵循统一命名规范:

Store 模块 标准函数 WithOut 函数
app.ts useAppStore useAppStoreWithOut
business.ts useBusinessStore useBusinessStoreWithOut
dict.ts useDictStore useDictStoreWithOut
locale.ts useLocaleStore useLocaleStoreWithOut

规则use{ModuleName}StoreWithOut — 模块名首字母大写 + Store + WithOut(注意大小写)。

实现清单

每个 store 模块必须:

  • 导出标准 useXxxStore 函数(defineStore 的返回值)
  • 导出 useXxxStoreWithOut 函数,内部调用 useXxxStore(store)
  • @/store 导入全局 store 实例
  • WithOut 函数放在文件底部,紧跟标准函数之后

为什么不直接使用 useXxxStore(pinia)

理论上可以直接调用 useAppStore(pinia),但 WithOut 函数提供了:

  1. 语义明确 — 函数名直接表达"在组件外使用"的意图
  2. 统一入口 — 不需要每个调用方都 import store,减少依赖
  3. 集中管理 — 如果 pinia 实例获取方式变更,只需改 WithOut 函数
  4. 可搜索 — 搜索 WithOut 即可找到所有组件外使用 store 的地方

替代方案:storeToRefs 注意事项

注意 useXxxStoreWithOut() 返回的是 store 实例,如需解构响应式属性,仍需使用 storeToRefs

import { storeToRefs } from 'pinia'
import { useAppStoreWithOut } from '@/store/modules/app'

export function useAppInfo() {
  const appStore = useAppStoreWithOut()
  const { pure, theme } = storeToRefs(appStore) // 保持响应式
  return { pure, theme }
}

总结

优势 说明
解决组件外访问 核心价值,让 store 可在任意上下文使用
命名约定清晰 WithOut 后缀一目了然
减少样板代码 调用方无需 import store
易于维护 pinia 实例变更只需改一处
可追溯 搜索 WithOut 可定位所有组件外使用