1. Pinia是什么?
Pinia是Vue官方推荐的状态管理库,是Vuex的替代品,专为Vue 3设计。它提供了一种简单、直观的方式来管理应用程序的状态。
Pinia的特点:
- 🔥 直观简单:API设计简洁,使用起来更加直观
- 🔄 完整的TypeScript支持:自动推断类型,提供更好的开发体验
- 🔌 模块化设计:可以创建多个独立的store,不需要像Vuex那样嵌套模块
- 🛠️ 开发工具支持:可以在Vue DevTools中查看和调试store
- ⚡ 轻量级:体积小,性能好
- 📱 SSR友好:支持服务端渲染
2. 为什么使用Pinia?
当我们的Vue应用变得复杂时,组件之间共享状态会变得困难。虽然可以使用props和emits在父子组件之间传递数据,但当组件层级变深或需要在不相关的组件之间共享数据时,这种方式就变得很麻烦。
Pinia解决了这个问题,它提供了一个中央存储库来管理应用的状态,任何组件都可以访问和修改这些状态。
3. 安装和设置Pinia
安装Pinia
npm install pinia
在Vue应用中设置Pinia
在main.js中:
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')
4. 创建Store
Pinia中的store是使用defineStore函数定义的。每个store都有一个唯一的ID。
基本Store结构
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
// 使用组合式API风格定义store
export const useCounterStore = defineStore('counter', () => {
// 状态(state)
const count = ref(0)
// 计算属性(getters)
const doubleCount = computed(() => count.value * 2)
// 动作(actions)
function increment() {
count.value++
}
// 返回需要暴露的内容
return { count, doubleCount, increment }
})
Store的三个核心概念
- State:存储的数据,相当于组件中的
data - Getters:计算属性,相当于组件中的
computed - Actions:方法,可以包含异步操作,相当于组件中的
methods
5. 在组件中使用Store
基本用法
<script setup>
import { useCounterStore } from '@/stores/counter'
// 获取store实例
const counterStore = useCounterStore()
// 现在可以在模板中使用store的状态和方法
</script>
<template>
<div>
<p>Count: {{ counterStore.count }}</p>
<p>Double Count: {{ counterStore.doubleCount }}</p>
<button @click="counterStore.increment()">Increment</button>
</div>
</template>
解构Store
如果想要解构store中的属性,需要使用storeToRefs函数来保持响应性:
<script setup>
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'
const counterStore = useCounterStore()
// 使用storeToRefs保持响应性
const { count, doubleCount } = storeToRefs(counterStore)
// 方法可以直接解构,不需要storeToRefs
const { increment } = counterStore
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<p>Double Count: {{ doubleCount }}</p>
<button @click="increment()">Increment</button>
</div>
</template>