状态管理是现代 Web 应用开发中的一个重要概念。Vue 3 中的状态管理库 Pinia
,是一个基于Vue 3 Composition API
的状态管理库,它提供了一种简单、灵活的方式来管理应用程序的状态,同时还具有高性能和可扩展性。Pinia
在某种程度上来说,也可以被叫做Vuex5
,因为它结合了Vuex 5
核心团队讨论中的许多想法,所以 Pinia
被作为新的推荐方案来代替Vuex
。
actions
、mutations
的时间线Store
Time travel
Store
State
actions
修改state
中的数据。废弃了mutation
。vuex
中的module
,每个Pinia
模块都是独立的Pinia
功能TypeScript
支持。提供了代码补全功能,避免了过多魔法字符串的注入。安装 Pinia 很简单,只需要使用 npm 或者 yarn 安装即可:
npm install pinia
# 或
yarn add pinia
创建一个 Pinia Store 非常简单,下面是一个简单的示例:
Tips
: 关于 Pinia Store 的命名,官方推荐的做法是 use+名称+Store。
import { defineStore } from 'pinia'
// 你可以对 `defineStore()` 的返回值进行任意命名,但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。(比如 `useUserStore`,`useCartStore`,`useProductStore`)
// 第一个参数是你的应用中 Store 的唯一 ID。
export const useCounterStore = defineStore({
id: "counter",
state: () => ({
count: 0,
}),
actions: {
increment() {
this.count++;
},
decrement() {
this.count--;
},
},
getters: {
doubleCount: ({ count }) => count * 2,
},
});
在上面的代码中,我们首先使用 defineStore
函数创建了一个名为 useCounterStore
的 Pinia Store,然后在 state
函数中定义了一个 count
属性,最后在 actions
对象中定义了 increment
和 decrement
两个方法来修改 count
属性。
当然了,我们用一个函数来定义 Store 也是同样可行的:
import { ref, computed } from "vue";
// 你可以对 `defineStore()` 的返回值进行任意命名,但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。(比如 `useUserStore`,`useCartStore`,`useProductStore`)
// 第一个参数是你的应用中 Store 的唯一 ID。
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2);
function increment() {
count.value++
}
function decrement() {
count.value--
}
return { count, doubleCount, increment, decrement }
})
要在组件中使用 Pinia Store,我们需要将 Store 导入进来。
<script setup lang="ts">
import { useCounterStore } from "@/stores/counter";
const counterStore = useCounterStore()
// 注意此处不能直接采用结构赋值的方法:如 const { count, doubleCount } = useCounterStore()
// 这样会让数据失去响应性
</script>
想结构赋值的话,需要导入 storeToRefs 函数,将解构出来的参数变成响应式:
<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { useCounterStore } from "@/stores/counter";
const counterStore = useCounterStore()
// 将解构出来的参数变成响应式
const { count, doubleCount } = storeToRefs(counterStore)
// 作为 action 的 increment 和 decrement 可以直接解构
const { increment, decrement } = counterStore
</script>
要在模板中使用 Pinia Store,我们在模板中直接使用就行了。
<template>
<div>
<p>Count: {{ counterStore.count }}p>
<p>doubleCount: {{ counterStore.doubleCount }}p>
<button @click="counterStore.increment()">Incrementbutton>
<button @click="counterStore.decrement()">Decrementbutton>
div>
template>
在Pinia
中,状态管理和数据流的概念非常重要。状态管理是指将应用程序的状态保存在一个中心化的地方,并通过一些方法来修改和查询状态。数据流是指数据在应用程序中的流动方式,包括数据的来源、传输、处理和存储等方面。
在Pinia
中,我们可以使用Store
来管理应用程序的状态,并使用Actions
和Getters
来修改和查询状态。Store
是一个包含状态、Actions 和 Getters 的对象,它可以被多个组件共享。当一个组件需要修改或查询状态时,它可以通过Store
来访问状态,并调用相应的Actions
或Getters
来修改或查询状态。
在Pinia
中,数据的流动方式非常简单和直观。当一个组件调用Store
中的Actions
来修改状态时,数据会从组件流向 Store
,然后从Store
再流向其他组件。当一个组件调用Store
中的Getters
来查询状态时,数据会从Store
流向组件。这种数据流的方式非常清晰和可控,使得我们可以更好地管理和维护应用程序的状态。
在 Pinia 中,我们可以使用模块化和命名空间来组织 Store,以便更好地管理和维护应用程序的状态。模块化和命名空间可以帮助我们将应用程序的状态分成多个逻辑模块,并将其组合成完整的应用程序状态。这种模块化和命名空间的方式非常清晰和可控,使得我们可以更好地管理和维护应用程序的状态。
在 Pinia 中,我们可以使用 defineStore
函数来定义一个 Store。defineStore
函数可以接受一个参数对象,其中包含了 Store 的状态、Actions 和 Getters 等信息。我们可以将多个 defineStore
函数组合成一个完整的 Store,以便更好地管理和维护应用程序的状态。
import { defineStore } from 'pinia'
const counterStore = defineStore({
id: 'counter',
state: () => ({
count: 0
}),
actions: {
increment() {
this.count++
},
decrement() {
this.count--
}
},
getters: {
doubleCount: (state) => state.count * 2,
},
})
const userStore = defineStore({
id: 'user',
state: () => ({
name: '',
email: ''
}),
actions: {
setName(name) {
this.name = name
},
setEmail(email) {
this.email = email
}
}
})
export default {
counterStore,
userStore
}
在上面的代码中,我们首先使用 defineStore
函数定义了一个名为 counterStore
的 Store,其中包含了计数器状态和增加和减少计数器值的 Actions。然后,我们又使用 defineStore
函数定义了一个名为 userStore
的 Store,其中包含了用户信息状态和修改用户名和电子邮件的 Actions。最后,我们将 counterStore
和 userStore
导出为一个对象,以便在其他组件中使用。
在 Pinia 中,我们可以使用命名空间来组织 Store。命名空间可以将多个 Store 分组,并将其组合成完整的应用程序状态。命名空间可以帮助我们更好地管理和维护应用程序的状态,避免了状态冲突和重复定义的问题。
import { createPinia } from 'pinia'
import { counterStore } from './counter'
import { userStore } from './user'
const pinia = createPinia()
pinia.useStore('counter', counterStore)
pinia.useStore('user', userStore)
export default pinia
在上面的代码中,我们首先使用 createPinia
函数创建了一个 Pinia 实例,然后使用 useStore
函数将 counterStore
和 userStore
添加到了 Pinia 实例中,并分别使用了 counter
和 user
命名空间。这意味着,在其他组件中,我们可以通过 this.$pinia.store.counter
和 this.$pinia.store.user
来访问计数器 Store 和用户信息 Store。
在 Pinia 中,我们可以使用插件来扩展其功能。插件可以是一个简单的对象,也可以是一个包含多个函数的对象。我们可以使用 use
函数来添加插件。
import { createPinia } from 'pinia'
const pinia = createPinia()
const myPlugin = {
// ...
}
pinia.use(myPlugin)
在上面的代码中,我们首先使用 createPinia
函数创建了一个 Pinia 实例,然后使用 use
函数将 myPlugin
添加到了 Pinia 实例中。
在 Pinia 中,我们可以使用异步操作来处理一些需要等待的数据。异步操作可以是一个 Promise,也可以是一个异步函数。我们可以使用 await
关键字来等待异步操作的结果。
import { defineStore } from 'pinia'
export const useUserStore = defineStore({
id: 'user',
state: () => ({
name: '',
email: ''
}),
actions: {
async fetchUser() {
const response = await fetch('/api/user')
const data = await response.json()
this.name = data.name
this.email = data.email
}
}
})
在上面的代码中,我们首先使用 defineStore
函数定义了一个名为 useUserStore
的 Store,其中包含了用户信息状态和异步获取用户信息的 fetchUser
方法。在 fetchUser
方法中,我们首先使用 fetch
函数获取用户信息的数据,然后使用 await
关键字等待 fetch
函数的结果,并将其解析为 JSON 格式。最后,我们将获取的数据赋值给 Store 的状态。