下面给你一套 「能直接复制用、结构清晰、企业级规范」的 Pinia 分组 + 模块间调用完整示例代码
✅ Vue 3
✅ TypeScript
✅ Pinia
✅ 模块化
✅ 有 state / getter / action
✅ 有模块间调用


一、目录结构(重点)

src/
├── store/
│   ├── modules/
│   │   ├── user.ts
│   │   └── order.ts
│   ├── index.ts
│   └── types.ts

二、类型定义(store/types.ts)

// 用户
export interface UserInfo {
  id: number
  name: string
}

// 订单
export interface Order {
  id: number
  title: string
  price: number
}

三、user 模块(store/modules/user.ts)

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import type { UserInfo } from '../types'

export const useUserStore = defineStore('user', () => {
  // ===== state =====
  const token = ref('')
  const userInfo = ref<UserInfo | null>(null)

  // ===== getter =====
  const isLogin = computed(() => !!token.value)

  // ===== action =====
  function setToken(val: string) {
    token.value = val
  }

  function setUserInfo(info: UserInfo) {
    userInfo.value = info
  }

  function logout() {
    token.value = ''
    userInfo.value = null
  }

  return {
    token,
    userInfo,
    isLogin,
    setToken,
    setUserInfo,
    logout,
  }
})

四、order 模块(store/modules/order.ts)

这里演示「调用 user 模块」

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { useUserStore } from './user'
import type { Order } from '../types'

export const useOrderStore = defineStore('order', () => {
  // ===== state =====
  const orderList = ref<Order[]>([])

  // ===== getter =====
  const totalPrice = computed(() =>
    orderList.value.reduce((sum, item) => sum + item.price, 0)
  )

  // ===== action =====
  function submitOrder(order: Order) {
    const userStore = useUserStore()

    if (!userStore.isLogin) {
      throw new Error('请先登录')
    }

    orderList.value.push(order)
  }

  return {
    orderList,
    totalPrice,
    submitOrder,
  }
})

关键点

const userStore = useUserStore()
userStore.isLogin

五、统一导出(store/index.ts)

import { createPinia } from 'pinia'
import type { App } from 'vue'

export const pinia = createPinia()

export function setupStore(app: App) {
  app.use(pinia)
}

// 模块统一导出
export * from './modules/user'
export * from './modules/order'

六、main.ts 注册

import { createApp } from 'vue'
import App from './App.vue'
import { setupStore } from './store'

const app = createApp(App)
setupStore(app)
app.mount('#app')

七、在组件中使用(完整示例)

1️⃣ 使用 user store

<script setup lang="ts">
import { useUserStore } from '@/store'

const userStore = useUserStore()
</script>

<template>
  <div>
    <p>是否登录:{{ userStore.isLogin }}</p>

    <button @click="userStore.setToken('abc123')">登录</button>
    <button @click="userStore.logout">退出</button>
  </div>
</template>

2️⃣ 使用 order store(并调用 user)

<script setup lang="ts">
import { useOrderStore } from '@/store'
import { useUserStore } from '@/store'

const orderStore = useOrderStore()
const userStore = useUserStore()
</script>

<template>
  <div>
    <button
      :disabled="!userStore.isLogin"
      @click="orderStore.submitOrder({ id: 1, title: '商品A', price: 99 })"
    >
      提交订单
    </button>

    <ul>
      <li v-for="item in orderStore.orderList" :key="item.id">
        {{ item.title }} - ¥{{ item.price }}
      </li>
    </ul>

    <p>总价:¥{{ orderStore.totalPrice }}</p>
  </div>
</template>

八、模块调用关系图(很重要)

App
 ├── useUserStore
 └── useOrderStore
        └── useUserStore(跨模块调用)

Pinia 官方推荐这种方式
✅ 无需 event bus
✅ 无层级嵌套


一、Pinia 是什么(核心认知)

✅ Vue 官方状态管理库
✅ Vuex 的继任者
✅ 专为 Vue 3 + Composition API 设计

核心特点:

  • 没有 mutations ✅
  • 完整的 TS 支持 ✅
  • 模块化天生支持 ✅
  • 支持 DevTools ✅
  • 支持服务端渲染(SSR)✅

二、Pinia 基础知识点(必会)

1️⃣ 创建 Pinia

import { createPinia } from 'pinia'

const pinia = createPinia()
app.use(pinia)

2️⃣ 定义 Store(两种写法)

✅ 组合式(推荐)

export const useUserStore = defineStore('user', () => {
  const token = ref('')

  function setToken(val: string) {
    token.value = val
  }

  return { token, setToken }
})

⚠️ 选项式(了解)

export const useUserStore = defineStore('user', {
  state: () => ({ token: '' }),
  actions: {
    setToken(val: string) {
      this.token = val
    },
  },
})

3️⃣ State(状态)

const count = ref(0)

等价于:

state: () => ({ count: 0 })

✅ 响应式
✅ 支持 ref / reactive


4️⃣ Getter(派生状态)

const double = computed(() => count.value * 2)

✅ 缓存
✅ 类似 Vue computed


5️⃣ Action(修改状态)

function increment() {
  count.value++
}

✅ 同步 / 异步都可以
✅ 不需要 mutation


三、Pinia 进阶知识点(中高级)

6️⃣ Store 的使用方式

const userStore = useUserStore()
userStore.setToken('xxx')

✅ 可在:

  • setup
  • 普通函数
  • service
  • 非组件代码中调用

7️⃣ 多 Store 之间通信

const userStore = useUserStore()
const orderStore = useOrderStore()

✅ 天然支持
✅ 无嵌套地狱


8️⃣ Store 分组 / 模块化

store/
├── user.ts
├── order.ts

✅ 推荐按业务拆分
✅ 不要一个 store 管全部


9️⃣ Store 重置(reset)

userStore.$reset()

✅ 重置为初始 state


🔟 订阅状态变化

userStore.$subscribe((mutation, state) => {
  console.log(mutation, state)
})

✅ 用于埋点 / 日志 / 调试


四、Pinia 高级知识点(企业级)

1️⃣1️⃣ 持久化(非常常见)

npm i pinia-plugin-persistedstate
export const useUserStore = defineStore(
  'user',
  () => { ... },
  {
    persist: true,
  }
)

1️⃣2️⃣ SSR / Nuxt 支持

const store = useUserStore(pinia)

✅ 同构渲染
✅ hydration 自动处理


1️⃣3️⃣ Store 的解构(必须知道)

❌ 错误(失去响应性)

const { token } = userStore

✅ 正确

import { storeToRefs } from 'pinia'

const { token } = storeToRefs(userStore)

1️⃣4️⃣ Store 作为参数传递(解耦)

function logout(userStore: ReturnType<typeof useUserStore>) {
  userStore.$reset()
}

1️⃣5️⃣ 自定义插件(高级)

export function myPiniaPlugin({ store }) {
  store.$onAction(({ name, args }) => {
    console.log(name, args)
  })
}

五、Pinia 与 Vuex 对比(面试高频)

对比项 Pinia Vuex
mutations
TS 支持 ✅✅✅ ⚠️
模块化 原生 手动
代码体积 更小 较大
官方态度 ✅ 推荐 ❌ 维护模式

六、Pinia 最佳实践(企业级总结)

✅ 一个业务一个 store
✅ 用组合式 API
✅ store 只管状态,不管请求
✅ 请求放在 service 层
✅ 大型项目用 domain 分层


七、Pinia 学习路线(建议)

基础用法
 ↓
模块化分组
 ↓
TS 类型设计
 ↓
持久化
 ↓
工程化拆分(store / service / model)
 ↓
性能 & 架构优化

下面我按 「面试标准答案 + 加分点」 的方式,把这 6 个 Pinia 高频问题一次性讲清楚,你可以直接背,也可以理解后用自己的话讲。


1️⃣ Pinia 和 Vuex 的区别?(必考)

✅ 标准答案

对比点 Pinia Vuex
官方定位 Vue3 官方推荐 Vue2 时代产物
mutations ❌ 移除 ✅ 必须有
actions 支持同步 / 异步 支持
模块化 天生支持 需要 namespace
TypeScript 原生友好 类型复杂
代码体积 更小 较大
心智模型 简单 偏重

✅ 加分一句话

Pinia 是 Vuex 的精神继承者,专门为 Vue 3 和 Composition API 设计。


2️⃣ 为什么 Pinia 不需要 mutation?

✅ 标准答案

  • mutation 的存在是为了 追踪同步变更
  • Pinia 使用 ref / reactive
  • Vue DevTools 已经能追踪 .value 的变化
  • 同步 / 异步都可以在 action 中完成

✅ 面试原话

在 Pinia 中,state 本身就是响应式的,action 可以直接修改 state,不再需要 mutation 这一层约束。


3️⃣ Pinia 的 state 本质是什么?

✅ 标准答案

组合式写法 中:

const count = ref(0)

👉 state 的本质就是 refreactive 对象

Pinia 内部会把它们收集起来,暴露给 DevTools 和插件。

✅ 一句话总结

Pinia 的 state = Composition API 的响应式数据


4️⃣ 如何在组件外使用 Pinia?(高频)

✅ 场景

  • service
  • utils
  • 请求拦截器
  • 非 Vue 文件

✅ 标准写法

import { createPinia } from 'pinia'

const pinia = createPinia()
const userStore = useUserStore(pinia)

✅ 在项目中(已注册)

import { useUserStore } from '@/store'

const userStore = useUserStore()

✅ 面试加分点

Pinia 不依赖组件上下文,只要传入 pinia 实例即可在任何地方使用。


5️⃣ Pinia 如何实现持久化?

✅ 标准答案(最常用)

使用官方生态插件:

npm i pinia-plugin-persistedstate
export const useUserStore = defineStore(
  'user',
  () => { ... },
  {
    persist: true,
  }
)

✅ 可配置

persist: {
  key: 'user-store',
  storage: localStorage,
}

✅ 加分点

Pinia 本身不负责持久化,通过插件机制实现,符合单一职责原则。


6️⃣ storeToRefs 是干嘛的?

✅ 问题背景

const { token } = userStore // ❌ 失去响应性

✅ 正确答案

import { storeToRefs } from 'pinia'

const { token } = storeToRefs(userStore)

✅ 原理简述

  • store 本身是 reactive
  • 直接解构会破坏响应性
  • storeToRefs 只把 state / getter 转成 ref

storeToRefs 用于在解构 Pinia store 时保留响应性。


Composition API
去掉 mutation
TypeScript 原生支持

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐