title: Claude Code 状态管理实战:Pinia 与复杂业务逻辑
date: 2026-07-07
category: AI 开发工具
tags: [Claude Code, Pinia, 状态管理, Vue 3, 复杂业务]

Claude Code 状态管理实战:Pinia 与复杂业务逻辑

当页面超过 5 个、组件之间存在多层嵌套通信时,props drilling 已经不够用了。本篇教你用 Claude 搭建基于 Pinia 的状态管理体系,处理多 Tab 页、全局配置、用户信息等复杂场景。

前言

在小型项目中,组件内的 refreactive 就够了。但一旦项目变大——用户需要在设置页修改主题色,所有页面立即生效;需要多 Tab 页切换时保留各自的搜索条件和表单数据;需要判断用户角色来控制菜单可见性——这些就是 Pinia 状态管理 的用武之地。

好消息是,Claude Code 对状态管理的理解非常到位。你只需要说清楚"哪些数据需要在组件间共享",它就能帮你搭建完整的 Pinia Store 架构。

一、什么时候该用 Pinia?

先判断哪些场景需要抽离到 Store:

场景 是否需要 Store 原因
单个页面内的表单数据 组件内 ref 足够
用户登录状态 全局共享
主题色/布局配置 多页面联动
多 Tab 页的搜索条件 Tab 间独立存储
面包屑导航路径 路由联动
组件间的 EventBus 通信 替代 $emit 冒泡

原则:如果同一个数据被 2 个以上组件读取或修改,就应该放进 Store。

二、搭建 Pinia 基础架构

2.1 初始化

帮我在项目中初始化 Pinia,创建 src/stores/ 目录结构

Claude 会执行 pnpm add pinia,创建 src/stores/index.ts,并在 main.ts 中注册。

2.2 用户信息 Store

创建一个 userStore,管理以下内容:
- 用户基本信息(id, username, name, avatar, roles)
- 登录/登出方法
- Token 的持久化(localStorage)
- 从后端获取用户详情的方法

Claude 生成的 src/stores/user.ts

import { ref } from 'vue'
import { defineStore } from 'pinia'
import { get } from '@/utils/http'
import type { UserInfo } from '@/api/types'

export const useUserStore = defineStore('user', () => {
  const token = ref(localStorage.getItem('token') || '')
  const userInfo = ref<UserInfo | null>(null)
  const roles = ref<string[]>([])

  // 登录
  async function login(username: string, password: string) {
    const res = await post('/auth/login', { username, password })
    token.value = res.token
    localStorage.setItem('token', res.token)
    await fetchUserInfo()
    return res
  }

  // 登出
  async function logout() {
    try {
      await post('/auth/logout')
    } finally {
      token.value = ''
      userInfo.value = null
      roles.value = []
      localStorage.removeItem('token')
      // 跳转登录页
      location.reload()
    }
  }

  // 获取用户信息
  async function fetchUserInfo() {
    const info = await get<UserInfo>('/user/info')
    userInfo.value = info
    roles.value = info.roles || []
    return info
  }

  return { token, userInfo, roles, login, logout, fetchUserInfo }
})

2.3 应用配置 Store

创建一个 appStore,管理:
- 侧边栏折叠状态
- 主题(亮色/暗色)
- 语言(中英文切换)
- 面包屑路径

Claude 生成的 src/stores/app.ts

import { ref, watch } from 'vue'
import { defineStore } from 'pinia'

export const useAppStore = defineStore('app', () => {
  const sidebarCollapsed = ref(false)
  const theme = ref<'light' | 'dark'>('light')
  const locale = ref<'zh-CN' | 'en-US'>('zh-CN')

  // 侧边栏折叠切换
  function toggleSidebar() {
    sidebarCollapsed.value = !sidebarCollapsed.value
  }

  // 主题切换
  function setTheme(newTheme: 'light' | 'dark') {
    theme.value = newTheme
    document.documentElement.classList.toggle('dark-theme', newTheme === 'dark')
  }

  // 持久化
  watch(
    [sidebarCollapsed, theme, locale],
    ([collapsed, t, loc]) => {
      localStorage.setItem('app-config', JSON.stringify({ collapsed, theme: t, locale: loc }))
    },
    { deep: true }
  )

  // 初始化时恢复
  const saved = localStorage.getItem('app-config')
  if (saved) {
    const config = JSON.parse(saved)
    sidebarCollapsed.value = config.collapsed ?? false
    theme.value = config.theme ?? 'light'
    locale.value = config.locale ?? 'zh-CN'
  }

  return { sidebarCollapsed, theme, locale, toggleSidebar, setTheme }
})

2.4 多 Tab 页缓存 Store

创建一个 tabsStore,实现多 Tab 页功能:
- 每个打开的页面作为一个 Tab
- Tab 列表存储在 store 中
- 关闭 Tab 时返回上一页
- 刷新页面时保留 Tab 状态

Claude 会创建一个基于 shallowRef 的 Tab 数组 Store,配合 watch 持久化到 sessionStorage。

三、复杂业务场景实战

3.1 动态路由 + 角色权限

需要根据用户角色动态生成路由。
管理员可以看到"系统设置"菜单,普通用户只能看到"首页"和"我的信息"。
让 Claude 实现基于角色的路由过滤。

Claude 会:

  1. 定义完整的路由表(包含 meta.roles 字段)
  2. fetchUserInfo 后过滤路由
  3. router.addRoute 动态注册可用路由
  4. 在导航守卫中检查权限

3.2 全局搜索历史

顶部导航栏有一个全局搜索框,搜索历史需要跨页面共享。
最近 10 条搜索记录存储在 Pinia 中,支持清除历史记录。

Claude 会创建一个 searchStore,在搜索组件中 useSearchStore() 读取和写入,任何页面搜索都会更新同一个状态。

3.3 表单草稿自动保存

用户填写长表单时,每 30 秒自动保存到 localStorage。
刷新页面后自动恢复草稿。
换页时提示是否保存草稿。

Claude 会创建一个通用的 draftStore,用 setInterval 定时序列化表单数据,在 onBeforeUnmount 时做最后一次保存,页面加载时恢复。

四、让 Claude 做 Store 重构

随着业务发展,最初的 Store 设计可能不够用了。比如:

我现在把所有状态都塞在了一个 appStore 里,太臃肿了。
帮我拆分成 user、app、settings 三个独立的 Store。

Claude 会:

  1. 分析 appStore 中的状态和方法
  2. 按职责拆分到三个新文件
  3. 找到所有引用旧 Store 的组件,更新 import
  4. 确保拆分后功能不受影响

4.1 Options API vs Composition API 风格的 Store

Pinia 支持两种写法:

// Composition API 风格(推荐)
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  function increment() { count.value++ }
  return { count, increment }
})

// Options API 风格(熟悉 Vue 2 写法的人 preferred)
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: {
    increment() { this.count++ }
  }
})
把现有的 Options API 风格的 Store 改成 Composition API 风格

Claude 会完成风格统一,并解释改动点。

五、Store 之间的依赖关系

实际项目中,Store 之间经常需要互相调用。比如 userStore 登录后需要更新 permissionStore

用户登录后,userStore 需要通知 permissionStore 重新加载路由权限。
帮我实现 Store 之间的联动。

Claude 的实现方式:

// stores/permission.ts
import { storeToRefs } from 'pinia'
import { useUserStore } from './user'

export const usePermissionStore = defineStore('permission', () => {
  const userStore = useUserStore()
  const dynamicRoutes = ref<RouteRecordRaw[]>([])

  // 监听用户角色变化
  watch(
    () => userStore.roles,
    (roles) => {
      if (roles.length > 0) {
        filterRoutes(roles)
      }
    },
    { immediate: true }
  )

  function filterRoutes(roles: string[]) {
    // 根据角色过滤路由
    dynamicRoutes.value = allRoutes.filter(route =>
      !route.meta?.roles || route.meta.roles.some(r => roles.includes(r))
    )
  }

  return { dynamicRoutes, filterRoutes }
})

关键点:Pinia 的 Store 可以在另一个 Store 中直接 useXxxStore() 互调,不需要额外配置。

六、调试 Store 问题

6.1 状态没有响应

我在组件中修改了 userStore.userInfo.name,但视图没有更新。

Claude 会诊断:

  • 是否直接替换了整个对象(userInfo.value = newData 没问题,但 userInfo.value = { ...userInfo.value, name: 'new' }reactive 下才安全)
  • 推荐使用 userInfo.value!.name = 'new'(直接修改属性)或 Object.assign(userInfo.value!, { name: 'new' })
  • 如果是 ref,提醒需要 .value

6.2 持久化冲突

我在两个标签页同时打开了应用,在一个标签页修改了主题色,
另一个标签页没有实时更新。

Claude 会添加 window.addEventListener('storage', ...) 监听,或在 Store 中用 BroadcastChannel API 实现跨标签页同步。

七、这一章的核心心得

  1. 按需拆分 Store——每个 Store 只做一件事,不要把所有状态塞进一个文件
  2. Composition API 风格更灵活——支持 Store 之间的互相引用和组合
  3. 持久化是标配——用户信息、主题配置、侧边栏状态都应该持久化
  4. Store 联动比 EventBus 更清晰——Pinia 原生支持 Store 互调,不需要额外的通信机制
  5. 让 Claude 做重构——Store 拆分、风格统一、性能优化,Claude 能精准定位所有引用点

八、下一步

状态管理解决了组件间的数据共享问题,但对于大型项目,光有前端还不够。下一篇我们将深入 Claude Code 的高级能力——多智能体协作(Agent),让 Claude 同时派出多个"分身"并行开发不同模块,把开发效率提升数倍。


系列目录:

  1. 初识 Claude Code:用自然语言打造第一个 Web 页面 ← 上一篇
  2. 页面级交互实战:表单、弹窗与数据联动 ← 上一篇
  3. 前后端联调:让 Claude 帮你打通 REST API ← 上一篇
  4. 状态管理:Pinia 与复杂业务逻辑 ← 本篇
  5. 深入 Claude Code:Agent 多智能体协作(待写)
  6. Claude 驱动的后端开发:Spring Boot + 数据库(待写)
  7. 工程化进阶:代码审查、调试与性能优化(待写)
  8. 高级玩法:工作流编排与团队协作(待写)

更多推荐