Pinia 备忘清单
这是一份 Pinia 状态管理库的备忘单,列出了 Pinia 的常用命令和操作。
入门
安装 Pinia
npm install pinia
# or
yarn add pinia
# or
pnpm add pinia
定义 Store
创建一个 store 文件(例如 src/stores/counter.js),并定义 store
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  actions: {
    increment() {
      this.count++
    }
  },
  getters: {
    doubleCount: (state) => state.count * 2
  }
})
热重载 Store
使用 Vite 时,你可以启用热重载功能:
if (import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(useCounterStore, import.meta.hot))
}
使用 Store
在组件中使用 store
<template>
  <div>
    <p>Count: {{ counterStore.count }}</p>
    <p>Double Count: {{ counterStore.doubleCount }}</p>
    <button @click="counterStore.increment">Increment</button>
  </div>
</template>
<script>
import { useCounterStore } from '@/stores/counter'
export default {
  setup() {
    const counterStore = useCounterStore()
    return {
      counterStore
    }
  }
}
</script>
Modules 模式
Pinia 不使用传统的 Vuex 模块模式。相反,推荐使用独立的 store 文件:
// src/stores/user.js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
  state: () => ({
    name: 'Alice',
    age: 25
  }),
  actions: {
    setName(name) {
      this.name = name
    }
  },
  getters: {
    isAdult: (state) => state.age >= 18
  }
})
使用 Options API
如果你更喜欢 Options API,可以这样使用 Pinia:
<script>
import { defineComponent } from 'vue'
import { useCounterStore } from '@/stores/counter'
export default defineComponent({
  setup() {
    const counterStore = useCounterStore()
    return {
      counterStore
    }
  }
})
</script>
高级用法
使用组合函数
你可以将 store 与组合函数一起使用:
// src/composables/useCounter.js
import { useCounterStore } from '@/stores/counter'
export function useCounter() {
  const counterStore = useCounterStore()
  return {
    count: counterStore.count,
    doubleCount: counterStore.doubleCount,
    increment: counterStore.increment
  }
}
插件
Pinia 支持插件。你可以编写插件来扩展 Pinia 的功能:
// src/plugins/piniaPlugin.js
export function piniaPlugin({ store }) {
  store.$onAction(({ name, store, args, after, onError }) => {
    console.log(`Action ${name} was called with args:`, args)
  })
}
// main.js
import { createPinia } from 'pinia'
import { piniaPlugin } from './plugins/piniaPlugin'
const pinia = createPinia()
pinia.use(piniaPlugin)
持久化状态
1. 安装  pinia-plugin-persist
npm  pinia-plugin-persist
2. 配置 Pinia 和 pinia-plugin-persist
在你的入口文件中配置 Pinia 和 pinia-plugin-persist。
⚠️ Vue 2 项目
import Vue from 'vue'
import vueCompositionApi from '@vue/composition-api'
import { createPinia, PiniaVuePlugin } from 'pinia'
import piniaPersist from 'pinia-plugin-persist'
import App from './App.vue'
Vue.use(vueCompositionApi)
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
pinia.use(piniaPersist)
new Vue({
  pinia,
  render: h => h(App)
}).$mount('#app')
Vue 3 项目:
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import piniaPersist from 'pinia-plugin-persist'
import App from './App.vue'
const pinia = createPinia()
pinia.use(piniaPersist)
createApp(App)
  .use(pinia)
  .mount('#app')
3. 创建 Store 并启用持久化
创建一个 Pinia store,并启用持久化存储。
// stores/userStore.js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('userStore', {
  state: () => ({
    firstName: 'S',
    lastName: 'L',
    accessToken: 'xxxxxxxxxxxxx'
  }),
  actions: {
    setToken(value) {
      this.accessToken = value
    }
  },
  persist: {
    enabled: true,
    strategies: [
      {
        storage: localStorage,
        paths: ['accessToken']
      }
    ]
  }
})
4. 使用 Store
在组件中使用创建好的 store。
// src/components/SomeComponent.vue
<template>
  <div>
    <p>{{ userStore.firstName }} {{ userStore.lastName }}</p>
    <p>{{ userStore.accessToken }}</p>
  </div>
</template>
<script>
import { useUserStore } from '@/stores/userStore'
export default {
  setup() {
    const userStore = useUserStore()
    
    return { userStore }
  }
}
</script>
SSR 支持
Pinia 支持服务端渲染 (SSR)。在你的 SSR 入口文件中创建 Pinia 实例:
import { createPinia } from 'pinia'
export function createApp() {
  const app = createSSRApp(App)
  const pinia = createPinia()
  app.use(pinia)
  return { app, pinia }
}
明白了,让我们来结合 pinia-plugin-persist 插件完善 Pinia 备忘清单。
使用 Vue Devtools
Pinia 可以与 Vue Devtools 一起使用。确保你安装了最新版本的 Vue Devtools,然后你可以在 Devtools 中查看和调试你的 Pinia store。
使用异步 Actions
Pinia 支持在 actions 中使用异步代码:
// src/stores/todo.js
import { defineStore } from 'pinia'
import axios from 'axios'
export const useTodoStore = defineStore('todo', {
  state: () => ({
    todos: []
  }),
  actions: {
    async fetchTodos() {
      const response = await axios.get('/api/todos')
      this.todos = response.data
    }
  }
})
测试 Pinia Store
你可以使用 Vue Test Utils 和 Jest 来测试你的 Pinia store:
// __tests__/counterStore.test.js
import { setActivePinia, createPinia } from 'pinia'
import { useCounterStore } from '@/stores/counter'
describe('Counter Store', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
  })
  it('increments the count', () => {
    const counterStore = useCounterStore()
    expect(counterStore.count).toBe(0)
    counterStore.increment()
    expect(counterStore.count).toBe(1)
  })
  it('returns double count', () => {
    const counterStore = useCounterStore()
    counterStore.count = 2
    expect(counterStore.doubleCount).toBe(4)
  })
})