reference/docs/pinia.md
h7ml 60c463b1cb
feats (docs): add Pinia Memo List (#672)
* feats (docs): add Pinia Memo List

Create a Pinia Memo List to document common commands and actions of the Pinia State Management Library in markdown format. Content includes getting started, creating Pinia instances, defining the Store, using the Store, and more

* docs(pinia): update link to pinia-plugin-persist documentation

Correct the documentation link for pinia-plugin-persist in the Pinia documentation
to point to the official documentation hosted on seb-l.github.io. This ensures
that readers will access the most up-to-date and correct information regarding
the usage of the pinia-plugin-persist library.
2024-06-25 05:24:36 +08:00

6.9 KiB
Raw Blame History

Pinia 备忘清单

这是一份 Pinia 状态管理库的备忘单,列出了 Pinia 的常用命令和操作。

入门

安装 Pinia

npm install pinia
# or
yarn add pinia
# or
pnpm add pinia

创建 Pinia 实例

在你的 Vue 应用中创建一个 Pinia 实例并将其传递给 Vue

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const app = createApp(App)
const pinia = createPinia()

app.use(pinia)
app.mount('#app')

定义 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

在组件中使用 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>

热重载 Store

使用 Vite 时,你可以启用热重载功能:

if (import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(useCounterStore, import.meta.hot))
}

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)

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 备忘清单。

持久化状态

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>

使用 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)
  })
})

另见