Pinia 是 Vue 的状态管理库,它提供了一种更简单、更不规范的 API 来管理应用的状态。Pinia 的设计哲学是简单性和易用性,它避免了 Vuex 中的许多复杂概念,如 mutations 和模块的嵌套结构,提供了一种更现代、更符合 Vue 3 Composition API 风格的状态管理方式。
先来瞅一眼 Pinia 的核心组件主要包括以下几个方面:
Store:Pinia 中的 Store 是一个保存状态和业务逻辑的实体,它不与组件树绑定,可以在整个应用中访问。Store 包含三个核心概念:state(状态)、getters(获取器)、actions(动作)。这些概念类似于组件中的 data、computed 和 methods。
defineStore() :这是定义 Store 的函数,需要传入一个独一无二的名字作为 ID,用于连接 Store 和 devtools。Store 可以通过 Setup 函数或 Option 对象来定义。
reactive:虽然 Pinia 本身不要求使用 Composition API,但它与 Vue 的 reactive 系统紧密集成,允许开发者以声明式的方式管理状态。
Devtools 支持:Pinia 支持 Vue Devtools,提供了追踪 actions 和 mutations 的时间线、时间旅行和热更新等功能,方便开发者调试。
插件系统:Pinia 允许通过插件来扩展其功能,例如支持服务器端渲染或添加额外的中间件。
TypeScript 支持:Pinia 提供了对 TypeScript 的良好支持,包括类型推断和自动补全功能,使得在 TypeScript 项目中使用 Pinia 更加方便 。
SSR 支持:Pinia 支持服务端渲染,这对于构建需要 SSR 的应用是一个重要的特性。
映射辅助函数:Pinia 提供了如 mapStores、mapState 和 mapActions 等辅助函数,使得在组件中使用 Store 更加方便。
下面是每个部分的详细介绍。
在 Pinia 中,Store
是用来封装应用的状态和逻辑的核心概念。它允许你将状态和行为集中管理,而不是分散在各个组件中。Store
可以包含以下几部分:
下面是一个创建 Store
的步骤解析,包括代码示例:
首先,你需要从 Pinia 导入 defineStore
函数,并使用它来定义一个新的 Store
。
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
users: [] // 初始状态是一个空数组
}),
getters: {
// 一个 getter 函数,返回数组中的用户数量
count: (state) => state.users.length
},
actions: {
// 一个 action 函数,用于添加用户
addUser(user) {
this.users.push(user)
}
}
})
在 Vue 组件中,你可以通过调用你定义的 useUserStore
函数来使用这个 Store
。
<template>
<div>
<button @click="addNewUser">添加用户</button>
<p>用户总数: {{ userCount }}</p>
<ul>
<li v-for="user in users" :key="user.id">{{ user.name }}</li>
</ul>
</div>
</template>
<script setup>
import { computed } from 'vue'
import useUserStore from '@/stores/user'
const store = useUserStore()
const users = computed(() => store.users)
const userCount = computed(() => store.count)
function addNewUser() {
store.addUser({ id: Date.now(), name: '新用户' })
}
</script>
defineStore
:从 Pinia 导入 defineStore
函数来定义新的 Store
。useUserStore
:创建一个名为 useUserStore
的函数,它返回一个 Store
对象。Store
中定义了一个状态 users
,初始为空数组。count
getter,它返回 users
数组的长度。addUser
action,它接受一个用户对象并将其添加到 users
数组中。<script setup>
块中,通过调用 useUserStore
来获取 Store
实例,并使用 computed
来创建响应式的 users
和 userCount
。addNewUser
函数,当按钮被点击时,调用 store.addUser
来添加新用户。以上案例展示了如何在 Pinia 中创建和管理状态,以及如何在 Vue 组件中使用 Store
。通过这种方式,你可以集中管理状态,使得状态逻辑更加清晰和可维护。
defineStore()
是 Pinia 中用于定义 Store 的函数。它允许你以声明式的方式创建一个状态管理单元,这个单元可以包含状态(state)、获取器(getters)、动作(actions)等。defineStore()
函数接受一个唯一的 ID 和一个配置对象,配置对象中可以定义 state、getters、actions 等属性。
下面是一个使用 defineStore()
创建 Store 的步骤解析,包括代码示例:
首先,需要从 Pinia 导入 defineStore
函数。
import { defineStore } from 'pinia'
使用 defineStore()
定义一个新的 Store,传入一个唯一的 ID 和一个配置对象。
export const useCartStore = defineStore('cart', {
state: () => ({
items: [] // 购物车初始状态为空数组
}),
getters: {
// 计算属性,返回购物车中商品的总数量
itemCount(state) {
return state.items.reduce((total, item) => total + item.quantity, 0)
}
},
actions: {
// 添加商品到购物车的动作
addItem(item) {
const index = this.items.findIndex(i => i.id === item.id)
if (index > -1) {
// 如果商品已存在,则增加数量
this.items[index].quantity += item.quantity
} else {
// 否则,添加新商品
this.items.push(item)
}
},
// 清空购物车的动作
clearCart() {
this.items = []
}
}
})
在 Vue 组件中,通过调用 useCartStore
来使用这个 Store。
<template>
<div>
<button @click="addItem">添加商品</button>
<button @click="clearCart">清空购物车</button>
<p>商品总数: {{ itemCount }}</p>
<ul>
<li v-for="item in cartItems" :key="item.id">
{{ item.name }} - 数量: {{ item.quantity }}
</li>
</ul>
</div>
</template>
<script setup>
import { computed } from 'vue'
import useCartStore from '@/stores/cart'
const store = useCartStore()
const cartItems = computed(() => store.items)
const itemCount = computed(() => store.itemCount)
function addItem() {
store.addItem({ id: 1, name: '商品A', quantity: 1 })
}
function clearCart() {
store.clearCart()
}
</script>
defineStore
函数。useCartStore
的函数,它返回一个配置好的 Store
对象。Store
中定义了一个状态 items
,初始为空数组,用于存储购物车中的商品。itemCount
getter,它通过遍历 items
数组并累加每个商品的 quantity
来计算总数量。addItem
和 clearCart
两个 actions。addItem
用于向购物车添加商品,如果商品已存在则增加其数量;clearCart
用于清空购物车。<script setup>
块中,通过调用 useCartStore
来获取 Store
实例,并使用 computed
来创建响应式的 cartItems
和 itemCount
。addItem
和 clearCart
函数,分别用于添加商品和清空购物车。使用 defineStore()
创建一个包含状态、获取器和动作的 Store,并在 Vue 组件中使用这个 Store 来管理购物车的状态。通过这种方式,你可以将状态逻辑封装在 Store 中,使得组件更加简洁和易于管理。
reactive()
是 Vue 3 的 Composition API 中的一个函数,它用于创建响应式的状态对象。当使用 reactive()
创建一个对象后,Vue 会追踪这个对象中属性的读取和修改,并且在数据变化时通知依赖于这些数据的组件重新渲染。
Pinia 与 Vue 的响应式系统紧密集成,reactive()
通常在定义 Store 的状态时使用。在 Pinia 中,状态(state)是一个通过 reactive()
创建的响应式对象,因此任何对状态的修改都会自动触发与该状态相关的组件更新。
下面是一个使用 reactive()
来创建响应式状态的步骤解析:
首先,需要从 Vue 导入 reactive
函数。
import { reactive } from 'vue'
使用 reactive()
函数来创建一个响应式的状态对象。
const state = reactive({
count: 0, // 初始状态
message: 'Hello, Pinia!' // 初始消息
})
在 Pinia 的 defineStore()
中,可以直接使用 reactive()
来定义状态。
import { defineStore } from 'pinia'
import { reactive } from 'vue'
export const useMyStore = defineStore('myStore', {
state: () => reactive({
count: 0,
message: 'Hello, Pinia!'
}),
// 其他 getters 和 actions 可以在这里定义
})
在 Vue 组件中,通过调用 useMyStore
来使用这个 Store,并访问响应式状态。
<template>
<div>
<p>Count: {{ count }}</p>
<p>Message: {{ message }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup>
import { computed } from 'vue'
import useMyStore from '@/stores/myStore'
const store = useMyStore()
const count = computed(() => store.state.count)
const message = computed(() => store.state.message)
function increment() {
store.state.count++
}
</script>
reactive
函数。reactive()
创建一个包含 count
和 message
的响应式状态对象。defineStore()
的 state
函数中返回一个 reactive()
对象,这样 Pinia 就可以管理这个状态的响应性。<script setup>
块中,通过调用 useMyStore
来获取 Store
实例。使用 computed
来确保访问状态时保持响应性。increment
函数,当按钮被点击时,直接修改 store.state.count
,这会触发组件的更新。通过这种方式,你可以确保状态的任何变化都会自动传播到使用这些状态的组件中,实现响应式的数据流,你get到了吗。
Vue Devtools 是一个浏览器扩展,它为开发 Vue 应用提供了强大的调试支持。对于 Pinia 来说,Devtools 支持意味着你可以在开发过程中更直观地查看和操作应用的状态。
Pinia 与 Vue Devtools 集成,提供了以下功能:
要充分利用 Pinia 的 Devtools 支持,你需要确保正确安装和配置了 Vue Devtools,并且正确地在你的 Pinia Store 中编写代码。来吧,一步一步跟着做就行:
首先,确保你已经安装了 Vue Devtools 浏览器扩展。你可以从 Chrome Web Store 或 Firefox Add-ons 等地方安装。
创建一个 Pinia Store,并定义 state、getters 和 actions。
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++
}
}
})
在你的 Vue 应用中创建 Pinia 实例,并在应用启动时使用它。
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')
在组件中使用你的 Store,并执行一些状态更改的动作。
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup>
import { computed } from 'vue'
import useCounterStore from '@/stores/counter'
const store = useCounterStore()
const count = computed(() => store.count)
function increment() {
store.increment()
}
</script>
defineStore
创建一个包含 state、getters 和 actions 的 Pinia Store。利用 Vue Devtools 提供的功能来调试使用 Pinia 管理状态的 Vue 应用,感觉是不是挺爽。
Pinia 的插件系统允许开发者扩展 Pinia 的功能。插件可以访问 Pinia 的 Store 创建过程,可以执行以下操作:
state
、getters
、actions
等属性。Pinia 插件通常在创建 Pinia 实例时注册,然后 Pinia 会将插件应用到每个创建的 Store 上。
下面是一个创建和使用 Pinia 插件的步骤解析,包括代码示例:
首先,定义一个插件函数,该函数接收 Pinia 的实例作为参数。
function myPiniaPlugin(pinia) {
// 插件逻辑
}
在插件函数内部,可以访问 Pinia 的 store
对象,并对其进行操作。
function myPiniaPlugin(pinia) {
pinia.use((store) => {
// 可以在此处访问 store.state, store.getters, store.actions 等
// 例如,向 store 添加一个新属性
store.myCustomProperty = 'Hello from plugin!'
})
}
创建 Pinia 实例时,使用 use
方法注册插件。
import { createPinia } from 'pinia'
const pinia = createPinia().use(myPiniaPlugin)
定义一个 Store,使用 defineStore
函数。
import { defineStore } from 'pinia'
export const useMyStore = defineStore('myStore', {
// state, getters, actions 定义
state: () => ({
value: 0
}),
// 其他选项...
})
在组件中使用 Store,并访问插件添加的属性。
<template>
<div>
<p>Value: {{ value }}</p>
<p>Plugin Property: {{ store.myCustomProperty }}</p>
</div>
</template>
<script setup>
import { computed } from 'vue'
import useMyStore from '@/stores/myStore'
const store = useMyStore()
const value = computed(() => store.value)
</script>
在组件的模板或脚本中,使用插件添加到 Store 的自定义属性。
// 在模板中
<p>Plugin Property: {{ store.myCustomProperty }}</p>
// 在脚本中
console.log(store.myCustomProperty) // 输出: Hello from plugin!
pinia.use
方法注册一个回调,该回调接收每个 Store 并可以对其进行操作。.use()
方法注册插件。defineStore
定义 Store,包括 state、getters、actions。记住这一点,开发者需要添加自定义逻辑和属性,通过Pinia 插件系统就 OK。
Pinia 为 TypeScript 用户提供了一流的支持,确保类型安全和开发体验。Pinia 的 TypeScript 支持主要体现在以下几个方面:
.d.ts
),确保 Pinia API 在 TypeScript 项目中的类型正确性。下面是一个使用 TypeScript 与 Pinia 结合使用的步骤解析,包括代码示例:
确保你的项目已经配置了 TypeScript,并且安装了必要的类型声明文件。
npm install typescript @vue/compiler-sfc
使用 TypeScript 的类型定义来创建 Pinia Store。
import { defineStore } from 'pinia'
interface State {
count: number
message: string
}
export const useMyStore = defineStore('myStore', {
state: (): State => ({
count: 0,
message: 'Hello, Pinia with TypeScript!'
}),
getters: {
// 使用 TypeScript 来声明 getter 的返回类型
doubleCount: (state): number => state.count * 2
},
actions: {
increment(): void {
this.count++
}
}
})
在 Vue 组件中使用 Store,并利用 TypeScript 提供类型安全。
<template>
<div>
<p>Count: {{ count }}</p>
<p>Message: {{ message }}</p>
<p>Double Count: {{ doubleCount }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import useMyStore from '@/stores/myStore'
const store = useMyStore()
const count = computed(() => store.count)
const message = computed(() => store.message)
const doubleCount = computed(() => store.doubleCount)
function increment() {
store.increment()
}
</script>
使用类型守卫来确保对 Store 属性的访问是安全的。
if (store.hasOwnProperty('count')) {
// TypeScript 知道 'count' 存在且为 number 类型
console.log(store.count)
}
interface
)来定义 Store 的状态类型。defineStore
并传入类型化的 state 函数,以及声明了返回类型的 getters 和 actions。hasOwnProperty
方法和类型守卫来安全地访问 Store 的属性。小结一下,Pinia 与 TypeScript 结合使用可以提供类型安全的状态管理,同时编辑器的自动补全和类型检查功能可以提高开发效率和减少错误。
服务器端渲染(SSR)是一种将网站页面在服务器上生成并发送给客户端的技术。对于状态管理库来说,SSR 支持意味着可以在服务器上初始化和操作状态,然后将状态序列化后发送到客户端,客户端再将这些状态恢复以保持与服务器端相同的状态。
Pinia 对 SSR 的支持主要体现在以下几个方面:
下面是一个使用 Pinia 进行 SSR 的步骤解析,包括代码示例:
首先,定义一个 Pinia Store。
import { defineStore } from 'pinia'
export const useMyStore = defineStore('myStore', {
state: () => ({
count: 0
}),
// 其他选项...
})
在服务器端,创建 Store 实例并初始化状态,然后将状态序列化。
// server.js
import { createPinia } from 'pinia'
import useMyStore from '@/stores/myStore'
const pinia = createPinia()
// 模拟从数据库获取初始状态
const initialState = { count: 10 }
// 创建 Store 实例并设置初始状态
const store = useMyStore(pinia)
store.$state.count = initialState.count
// 序列化状态
const stateToTransfer = JSON.stringify(store.$state)
在客户端,接收服务器端发送的状态,然后恢复到对应的 Store 中。
// client.js
import { createPinia } from 'pinia'
import { createApp } from 'vue'
import App from './App.vue' // Vue 应用的根组件
import useMyStore from '@/stores/myStore'
const pinia = createPinia()
// 假设从服务器接收的状态如下
const stateFromServer = JSON.parse(/* state serialized from server */)
// 创建 Store 实例并恢复状态
const store = useMyStore(pinia)
store.$state.count = stateFromServer.count
const app = createApp(App)
app.use(pinia)
app.mount('#app')
在 Vue 组件中,像平常一样使用 Store。
<template>
<div>{{ count }}</div>
</template>
<script setup>
import { computed } from 'vue'
import useMyStore from '@/stores/myStore'
const store = useMyStore()
const count = computed(() => store.count)
</script>
defineStore
定义一个 Pinia Store。JSON.stringify
序列化状态。$state
中。一句话,Pinia支持SSR有助于提高应用的初始加载性能和SEO优化。
在 Pinia 中,映射辅助函数用于将 Store 中的状态(state)、获取器(getters)、动作(actions)映射到组件的计算属性(computed properties)、方法(methods)或响应式属性上。这些辅助函数提供了一种便捷的方式来使用 Store,而无需在每个组件中重复编写相同的代码。
Pinia 的映射辅助函数主要包括:
mapState
:将 Store 中的状态映射为组件的计算属性。mapGetters
:将 Store 中的获取器映射为组件的计算属性。mapActions
:将 Store 中的动作映射为组件的方法。下面是一个使用 Pinia 映射辅助函数的步骤解析,包括代码示例:
首先,定义一个 Pinia Store。
import { defineStore } from 'pinia'
export const useCartStore = defineStore('cart', {
state: () => ({
items: []
}),
getters: {
itemCount: (state) => state.items.length
},
actions: {
addItem(item) {
this.items.push(item)
}
}
})
在组件中,使用 mapState
、mapGetters
和 mapActions
将 Store 的属性映射到组件上。
<template>
<div>
<p>Item Count: {{ itemCount }}</p>
<button @click="addItem({ id: 1, name: 'Apple' })">Add Apple</button>
</div>
</template>
<script setup>
import { mapState, mapGetters, mapActions } from 'pinia'
import useCartStore from '@/stores/cart'
const store = useCartStore()
// 使用 mapState 映射状态
const items = mapState(store, 'items')
// 使用 mapGetters 映射获取器
const itemCount = mapGetters(store, 'itemCount')
// 使用 mapActions 映射动作
const { addItem } = mapActions(store, ['addItem'])
</script>
在组件的模板中,直接使用映射的计算属性和方法。
<p>Item Count: {{ itemCount }}</p>
<button @click="addItem({ id: 1, name: 'Apple' })">Add Apple</button>
defineStore
定义一个包含状态、获取器和动作的 Pinia Store。mapState
:将 items
状态映射为组件的计算属性。mapGetters
:将 itemCount
获取器映射为组件的计算属性。mapActions
:将 addItem
动作映射为组件的方法。itemCount
来显示项目数量,使用映射的方法 addItem
来添加新项目。使用映射辅助函数,Pinia 可以让开发者以声明式的方式在组件中使用 Store 的状态和行为,从而减少样板代码并提高组件的可读性和可维护性。此外,这些辅助函数还有助于保持响应性,确保当 Store 中的状态变化时,组件能够自动更新。
不得不说,Pinia 提供了一种灵活且高效的方式来管理 Vue 应用的状态,无论是在单页应用还是服务器端渲染的场景下,都有出色的表现,写完收工,欢迎关注威哥爱编程,一起走全栈之路。