ToolkitX
知识库工具箱

Pinia 状态管理

store 定义、actions、getters

20min·进阶

01. 为什么需要状态管理

组件之间传数据用 props 和 emit 在简单场景下够用,但一旦项目变大,组件层级多,兄弟组件之间传数据就变成噩梦了。Pinia 是 Vue 的官方状态管理库,相当于把所有组件共享的数据抽到一个仓库里,谁要用谁去拿。就像一个中央冰箱,大家往里面放菜拿菜,不用端来端去了。
javascript
// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: { doubleCount: (state) => state.count * 2 },
  actions: { increment() { this.count++ } }
})

02. State、Getters 和 Actions

State 就是数据,相当于组件里的 data。Getters 是计算属性,根据 state 推导出新的值,跟组件里的 computed 一模一样。Actions 是改数据的方法,里面可以写异步逻辑,同步异步都能处理。注意 Actions 里用 this 直接访问 state 和其他 action。
javascript
import { useCounterStore } from '@/stores/counter'

const counterStore = useCounterStore()
counterStore.count        // 读取
counterStore.doubleCount  // 读取 getter
counterStore.increment()  // 调用 action
直接改 store.count 也可以,但最好养成通过 action 修改的习惯。

03. 组合式 API 风格写 Store

除了选项式写法,Pinia 还支持用组合式 API 写 store,跟写 composable 函数一样。用 setup 函数替代 state/getters/actions 分开的写法。ref 定义的就是 state,computed 就是 getters,普通函数就是 actions。这种写法更灵活,推荐用这种方式。
javascript
export const useUserStore = defineStore('user', () => {
  const user = ref(null)
  const isLoggedIn = computed(() => !!user.value)
  async function login(email, pwd) {
    user.value = await apiLogin(email, pwd)
  }
  return { user, isLoggedIn, login }
})

04. Store 之间的互相调用

真实项目里 store 之间经常需要互相调用。比如购物车 store 需要访问用户 store 里的用户信息。直接在一个 store 里 import 另一个 store 用就行了。Pinia 不存在像 Vuex 里 module 那种嵌套的概念,所有 store 都是扁平的,直接交叉引用。
javascript
export const useCartStore = defineStore('cart', () => {
  const userStore = useUserStore()
  async function checkout() {
    if (!userStore.isLoggedIn) throw new Error('请先登录')
    await apiCheckout(userStore.user.id)
  }
  return { checkout }
})

05. Pinia 持久化和插件

Pinia 有插件机制可以在每次 state 变化时做额外的事。最常用的场景是把 state 存到 localStorage 里,刷新页面数据不丢失。也可以自己写插件把 state 同步到后端、打日志、或者做调试。
javascript
import { createPinia } from 'pinia'

const pinia = createPinia()
pinia.use(({ store }) => {
  const saved = localStorage.getItem(store.$id)
  if (saved) store.$patch(JSON.parse(saved))
  store.$subscribe(() => {
    localStorage.setItem(store.$id, JSON.stringify(store.$state))
  })
})
敏感数据不要存 localStorage,任何人都能看到。

知识测验

1/4正确 0

Pinia 中 State 对应什么?

下一节

组件设计

下一节