编程进阶网 编程进阶网
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • Android提升进阶

  • iOS开发和进阶

  • Web开发和进阶

    • README
    • HTML工具手册

    • TypeScript入门

    • Vue高级进阶

      • 基础入门
      • 组件开发
      • 响应式系统
      • 路由管理
      • 状态管理
        • 5.1 状态管理概述
          • 5.1.1 为什么需要状态管理
          • 5.1.2 Pinia介绍
          • 5.1.3 安装和配置Pinia
          • 5.1.4 综合案例与思考
        • 5.2 定义Store
          • 5.2.1 Setup Store写法
          • 5.2.2 Option Store写法
          • 5.2.3 State状态
          • 5.2.4 Getters计算属性
          • 5.2.5 Actions方法
          • 5.2.6 综合案例与思考
        • 5.3 使用Store
          • 5.3.1 在组件中使用
          • 5.3.2 解构Store
          • 5.3.3 修改State
          • 5.3.4 订阅变化
          • 5.3.5 综合案例与思考
        • 5.4 Store进阶
          • 5.4.1 Store间相互调用
          • 5.4.2 状态持久化
          • 5.4.3 插件机制
          • 5.4.4 综合案例与思考
      • 组合式API
      • 工程化实战
  • Linux应用开发

  • Apps
  • Web开发和进阶
  • Vue高级进阶
杨充
2026-04-23
目录

状态管理

# 05.状态管理

# 目录介绍

  • 5.1 状态管理概述
    • 5.1.1 为什么需要状态管理
    • 5.1.2 Pinia介绍
    • 5.1.3 安装和配置Pinia
    • 5.1.4 综合案例与思考
  • 5.2 定义Store
    • 5.2.1 Setup Store写法
    • 5.2.2 Option Store写法
    • 5.2.3 State状态
    • 5.2.4 Getters计算属性
    • 5.2.5 Actions方法
    • 5.2.6 综合案例与思考
  • 5.3 使用Store
    • 5.3.1 在组件中使用
    • 5.3.2 解构Store
    • 5.3.3 修改State
    • 5.3.4 订阅变化
    • 5.3.5 综合案例与思考
  • 5.4 Store进阶
    • 5.4.1 Store间相互调用
    • 5.4.2 状态持久化
    • 5.4.3 插件机制
    • 5.4.4 综合案例与思考

# 5.1 状态管理概述

# 5.1.1 为什么需要状态管理

当多个组件需要共享状态时,Props层层传递变得笨重,状态管理提供集中化的解决方案:

没有状态管理(Props 钻透):
App → Layout → Sidebar → UserInfo    (逐层传递 user 数据)
App → Layout → Content → Header      (又要逐层传递 user 数据)

使用状态管理(Pinia):
┌──────────────────┐
│    Pinia Store    │  ← 集中管理状态
│  { user, cart }   │
└──────────────────┘
   ↕         ↕
UserInfo   Header   ← 任何组件直接读写,无需Props传递
1
2
3
4
5
6
7
8
9
10
11

适合使用状态管理的场景:

  • 用户登录信息(多个页面需要)
  • 购物车数据(多个组件需要读写)
  • 全局配置(主题、语言、权限)
  • 多组件共享的列表数据

# 5.1.2 Pinia介绍

Pinia 是 Vue 官方推荐的状态管理库,是 Vuex 的继任者:

对比项 Pinia Vuex
版本适配 Vue 2/3 Vue 2(Vuex3)/3(Vuex4)
TypeScript 完善支持 支持较弱
Mutation 无(直接修改State) 必须通过Mutation
模块化 天然模块化(多Store) 需要手动配置module
体积 ~1KB ~10KB
DevTools 完善支持 完善支持

# 5.1.3 安装和配置Pinia

npm install pinia
1
// src/main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const app = createApp(App)
app.use(createPinia())  // 注册 Pinia
app.mount('#app')
1
2
3
4
5
6
7
8

# 5.1.4 综合案例与思考

思考题:

  1. 什么时候应该使用 Pinia,什么时候用组件本地状态就够了?
  2. Pinia 为什么去掉了 Vuex 的 Mutation?直接修改State不会有问题吗?
  3. Pinia 的"天然模块化"是什么意思?和 Vuex 的 module 有什么区别?

# 5.2 定义Store

# 5.2.1 Setup Store写法

类似组件的 <script setup>,使用组合式API风格定义 Store(推荐):

// src/stores/counter.ts
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', () => {
  // ref() → state
  const count = ref(0)
  const name = ref('计数器')

  // computed() → getters
  const doubleCount = computed(() => count.value * 2)
  const displayText = computed(() => `${name.value}: ${count.value}`)

  // function → actions
  function increment() {
    count.value++
  }

  function decrement() {
    if (count.value > 0) count.value--
  }

  async function incrementAsync() {
    await new Promise(resolve => setTimeout(resolve, 1000))
    count.value++
  }

  // 必须返回所有需要暴露的状态和方法
  return { count, name, doubleCount, displayText, increment, decrement, incrementAsync }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 5.2.2 Option Store写法

类似 Vue 2 的选项式API:

// src/stores/counter.ts
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  // state:返回初始状态的函数
  state: () => ({
    count: 0,
    name: '计数器'
  }),

  // getters:类似计算属性
  getters: {
    doubleCount: (state) => state.count * 2,
    displayText(): string {
      return `${this.name}: ${this.count}`  // 可以用 this 访问
    }
  },

  // actions:方法(可以是异步的)
  actions: {
    increment() {
      this.count++  // 通过 this 访问 state
    },
    async fetchData() {
      const response = await fetch('/api/count')
      this.count = await response.json()
    }
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 5.2.3 State状态

// Setup Store 中的 State
export const useUserStore = defineStore('user', () => {
  // 基本类型
  const name = ref('')
  const age = ref(0)
  const isLoggedIn = ref(false)

  // 复杂类型
  const profile = ref<{
    avatar: string
    email: string
    roles: string[]
  } | null>(null)

  // 数组
  const permissions = ref<string[]>([])

  // 重置状态
  function reset() {
    name.value = ''
    age.value = 0
    isLoggedIn.value = false
    profile.value = null
    permissions.value = []
  }

  return { name, age, isLoggedIn, profile, permissions, reset }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 5.2.4 Getters计算属性

export const useCartStore = defineStore('cart', () => {
  const items = ref<Array<{ id: number; name: string; price: number; quantity: number }>>([])

  // 基础 getter
  const totalItems = computed(() =>
    items.value.reduce((sum, item) => sum + item.quantity, 0)
  )

  // 依赖其他 getter
  const subtotal = computed(() =>
    items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
  )

  const shipping = computed(() => subtotal.value >= 99 ? 0 : 10)

  const total = computed(() => subtotal.value + shipping.value)

  // 返回函数的 getter(接受参数)
  const getItemById = computed(() => {
    return (id: number) => items.value.find(item => item.id === id)
  })

  return { items, totalItems, subtotal, shipping, total, getItemById }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 5.2.5 Actions方法

export const useAuthStore = defineStore('auth', () => {
  const token = ref('')
  const user = ref<any>(null)
  const loading = ref(false)
  const error = ref('')

  const isLoggedIn = computed(() => !!token.value)

  // 同步 action
  function setToken(newToken: string) {
    token.value = newToken
    localStorage.setItem('token', newToken)
  }

  // 异步 action
  async function login(username: string, password: string) {
    loading.value = true
    error.value = ''
    try {
      const response = await fetch('/api/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ username, password })
      })
      if (!response.ok) throw new Error('登录失败')
      const data = await response.json()
      token.value = data.token
      user.value = data.user
      localStorage.setItem('token', data.token)
    } catch (e: any) {
      error.value = e.message
      throw e
    } finally {
      loading.value = false
    }
  }

  function logout() {
    token.value = ''
    user.value = null
    localStorage.removeItem('token')
  }

  return { token, user, loading, error, isLoggedIn, setToken, login, logout }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 5.2.6 综合案例与思考

综合案例:完整的待办事项Store

// stores/todo.ts
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'

interface Todo {
  id: number
  text: string
  done: boolean
  createdAt: Date
}

export const useTodoStore = defineStore('todo', () => {
  const todos = ref<Todo[]>([])
  const filter = ref<'all' | 'active' | 'done'>('all')
  let nextId = 1

  // Getters
  const filteredTodos = computed(() => {
    switch (filter.value) {
      case 'active': return todos.value.filter(t => !t.done)
      case 'done': return todos.value.filter(t => t.done)
      default: return todos.value
    }
  })

  const stats = computed(() => ({
    total: todos.value.length,
    active: todos.value.filter(t => !t.done).length,
    done: todos.value.filter(t => t.done).length
  }))

  // Actions
  function addTodo(text: string) {
    todos.value.push({
      id: nextId++,
      text: text.trim(),
      done: false,
      createdAt: new Date()
    })
  }

  function toggleTodo(id: number) {
    const todo = todos.value.find(t => t.id === id)
    if (todo) todo.done = !todo.done
  }

  function removeTodo(id: number) {
    todos.value = todos.value.filter(t => t.id !== id)
  }

  function clearDone() {
    todos.value = todos.value.filter(t => !t.done)
  }

  function setFilter(newFilter: 'all' | 'active' | 'done') {
    filter.value = newFilter
  }

  return {
    todos, filter, filteredTodos, stats,
    addTodo, toggleTodo, removeTodo, clearDone, setFilter
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<!-- TodoApp.vue -->
<template>
  <div class="todo-app">
    <h2>待办事项</h2>
    <input v-model="newText" @keyup.enter="add" placeholder="添加新任务" />

    <div class="filters">
      <button v-for="f in ['all', 'active', 'done']" :key="f"
        :class="{ active: store.filter === f }"
        @click="store.setFilter(f as any)">
        {{ { all: '全部', active: '未完成', done: '已完成' }[f] }}
      </button>
    </div>

    <ul>
      <li v-for="todo in store.filteredTodos" :key="todo.id">
        <input type="checkbox" :checked="todo.done" @change="store.toggleTodo(todo.id)" />
        <span :class="{ done: todo.done }">{{ todo.text }}</span>
        <button @click="store.removeTodo(todo.id)">删除</button>
      </li>
    </ul>

    <p>总计 {{ store.stats.total }} | 未完 {{ store.stats.active }} | 完成 {{ store.stats.done }}</p>
    <button v-if="store.stats.done > 0" @click="store.clearDone">清除已完成</button>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { useTodoStore } from '@/stores/todo'

const store = useTodoStore()
const newText = ref('')

const add = () => {
  if (newText.value.trim()) {
    store.addTodo(newText.value)
    newText.value = ''
  }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

思考题:

  1. Setup Store 和 Option Store 哪种写法更好?各有什么优缺点?
  2. Store 中的 getters 和组件中的 computed 有什么区别?为什么要放在 Store 里?
  3. 异步 action 中的错误处理应该怎么设计?错误信息放在 Store 里还是组件里?

# 5.3 使用Store

# 5.3.1 在组件中使用

<template>
  <p>{{ counterStore.count }}</p>
  <p>{{ counterStore.doubleCount }}</p>
  <button @click="counterStore.increment()">+1</button>
</template>

<script setup lang="ts">
import { useCounterStore } from '@/stores/counter'

// 调用 useXxxStore() 获取 store 实例
const counterStore = useCounterStore()

// 可以直接访问 state、getters、actions
console.log(counterStore.count)        // state
console.log(counterStore.doubleCount)   // getter
counterStore.increment()                // action
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 5.3.2 解构Store

直接解构 Store 会丢失响应式,需要用 storeToRefs:

<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { useCounterStore } from '@/stores/counter'

const store = useCounterStore()

// ❌ 错误:解构后 count 不再是响应式
// const { count, doubleCount } = store

// ✅ 正确:使用 storeToRefs 保持响应式
const { count, doubleCount, displayText } = storeToRefs(store)

// 注意:actions(方法)不需要 storeToRefs,直接解构
const { increment, decrement } = store
</script>

<template>
  <p>{{ count }}</p>
  <p>{{ doubleCount }}</p>
  <button @click="increment">+1</button>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 5.3.3 修改State

<script setup lang="ts">
import { useCounterStore } from '@/stores/counter'

const store = useCounterStore()

// 方式一:直接修改
store.count++

// 方式二:$patch 批量修改(推荐)
store.$patch({
  count: store.count + 1,
  name: '新名称'
})

// 方式三:$patch 函数形式(适合数组操作)
store.$patch((state) => {
  state.count++
  state.name = '新名称'
})

// 方式四:通过 action 修改(最推荐)
store.increment()

// 方式五:$reset 重置到初始状态(仅 Option Store 支持)
// store.$reset()
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 5.3.4 订阅变化

<script setup lang="ts">
import { useCounterStore } from '@/stores/counter'

const store = useCounterStore()

// 订阅 state 变化
store.$subscribe((mutation, state) => {
  console.log('变化类型:', mutation.type)  // 'direct' | 'patch object' | 'patch function'
  console.log('变化的 key:', mutation.events)
  console.log('新状态:', state)

  // 可以在这里做持久化
  localStorage.setItem('counter', JSON.stringify(state))
})

// 订阅 action 调用
store.$onAction(({ name, args, after, onError }) => {
  console.log(`Action "${name}" 被调用,参数:`, args)

  after((result) => {
    console.log(`Action "${name}" 执行完成,返回:`, result)
  })

  onError((error) => {
    console.error(`Action "${name}" 失败:`, error)
  })
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 5.3.5 综合案例与思考

综合案例:用户认证与多组件共享

// stores/auth.ts
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'

export const useAuthStore = defineStore('auth', () => {
  const token = ref(localStorage.getItem('token') || '')
  const user = ref<{ name: string; role: string } | null>(null)

  const isLoggedIn = computed(() => !!token.value)
  const isAdmin = computed(() => user.value?.role === 'admin')

  async function login(username: string, password: string) {
    // 模拟登录
    await new Promise(r => setTimeout(r, 1000))
    token.value = 'mock-token-' + Date.now()
    user.value = { name: username, role: username === 'admin' ? 'admin' : 'user' }
    localStorage.setItem('token', token.value)
  }

  function logout() {
    token.value = ''
    user.value = null
    localStorage.removeItem('token')
  }

  return { token, user, isLoggedIn, isAdmin, login, logout }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!-- Header.vue:显示用户信息 -->
<template>
  <header>
    <span v-if="isLoggedIn">欢迎, {{ user?.name }}</span>
    <button v-if="isLoggedIn" @click="logout">退出</button>
    <button v-else @click="$router.push('/login')">登录</button>
  </header>
</template>

<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { useAuthStore } from '@/stores/auth'

const authStore = useAuthStore()
const { isLoggedIn, user } = storeToRefs(authStore)
const { logout } = authStore
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

思考题:

  1. 为什么解构 Store 会丢失响应式?storeToRefs 做了什么?
  2. $patch 批量修改和直接逐个修改,在性能上有什么区别?
  3. $subscribe 和 watch 都能监听变化,各有什么优势?

# 5.4 Store进阶

# 5.4.1 Store间相互调用

// stores/user.ts
import { defineStore } from 'pinia'
import { useAuthStore } from './auth'

export const useUserStore = defineStore('user', () => {
  const profile = ref<any>(null)

  async function fetchProfile() {
    // 在一个 store 中使用另一个 store
    const authStore = useAuthStore()
    if (!authStore.isLoggedIn) {
      throw new Error('未登录')
    }

    const response = await fetch('/api/profile', {
      headers: { Authorization: `Bearer ${authStore.token}` }
    })
    profile.value = await response.json()
  }

  return { profile, fetchProfile }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 5.4.2 状态持久化

使用 pinia-plugin-persistedstate 插件实现自动持久化:

npm install pinia-plugin-persistedstate
1
// main.ts
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
1
2
3
4
5
6
// 在 Store 中启用持久化
export const useSettingsStore = defineStore('settings', () => {
  const theme = ref('light')
  const language = ref('zh-CN')
  const fontSize = ref(14)

  return { theme, language, fontSize }
}, {
  persist: {
    key: 'app-settings',           // localStorage 的 key
    storage: localStorage,          // 存储方式
    pick: ['theme', 'language']    // 只持久化指定字段
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 5.4.3 插件机制

自定义 Pinia 插件扩展功能:

// plugins/logPlugin.ts
import type { PiniaPluginContext } from 'pinia'

// 日志插件:记录所有 action 的调用
export function logPlugin({ store }: PiniaPluginContext) {
  store.$onAction(({ name, args, after, onError }) => {
    const start = Date.now()
    console.log(`[${store.$id}] Action "${name}" 开始`, args)

    after((result) => {
      console.log(`[${store.$id}] Action "${name}" 完成 (${Date.now() - start}ms)`, result)
    })

    onError((error) => {
      console.error(`[${store.$id}] Action "${name}" 失败 (${Date.now() - start}ms)`, error)
    })
  })
}

// 注册插件
// pinia.use(logPlugin)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 5.4.4 综合案例与思考

综合案例:多Store协作的电商应用

// stores/product.ts
export const useProductStore = defineStore('product', () => {
  const products = ref<any[]>([])
  const loading = ref(false)

  async function fetchProducts() {
    loading.value = true
    // 模拟API请求
    await new Promise(r => setTimeout(r, 500))
    products.value = [
      { id: 1, name: 'Vue教程', price: 99, stock: 10 },
      { id: 2, name: 'TS手册', price: 59, stock: 5 },
      { id: 3, name: 'Vite指南', price: 79, stock: 8 }
    ]
    loading.value = false
  }

  return { products, loading, fetchProducts }
})

// stores/cart.ts
export const useCartStore = defineStore('cart', () => {
  const items = ref<Array<{ id: number; name: string; price: number; quantity: number }>>([])

  const total = computed(() =>
    items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
  )

  function addItem(product: { id: number; name: string; price: number }) {
    // 调用 productStore 检查库存
    const productStore = useProductStore()
    const p = productStore.products.find(p => p.id === product.id)
    const cartItem = items.value.find(i => i.id === product.id)
    const currentQty = cartItem ? cartItem.quantity : 0

    if (p && currentQty >= p.stock) {
      throw new Error('库存不足')
    }

    if (cartItem) {
      cartItem.quantity++
    } else {
      items.value.push({ ...product, quantity: 1 })
    }
  }

  function removeItem(id: number) {
    items.value = items.value.filter(i => i.id !== id)
  }

  return { items, total, addItem, removeItem }
}, {
  persist: true  // 购物车持久化
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

思考题:

  1. Store 之间相互调用时,如何避免循环依赖?
  2. 状态持久化时,哪些数据适合持久化,哪些不适合?为什么 loading 状态不应该持久化?
  3. Pinia 插件能做什么?你能想到哪些实用的插件场景?
上次更新: 2026/06/10, 11:13:41
路由管理
组合式API

← 路由管理 组合式API→

最近更新
01
信号崩溃快速排查
06-15
02
CoreDump破案
06-15
03
perf火焰图实战
06-15
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式