Pinia 状态管理:比 Vuex 更简单
Pinia 状态管理:比 Vuex 更简单
当项目变大,多个组件需要共享数据时,就需要状态管理。Pinia 是 Vue 3 官方推荐的状态管理库,比 Vuex 更简单。
安装
pnpm add pinia
在 main.ts 中注册:
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
const app = createApp(App)
app.use(createPinia())
app.mount('#app')
创建第一个 Store
创建 src/stores/counter.ts:
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
function increment() {
count.value++
}
function reset() {
count.value = 0
}
return { count, increment, reset }
})
在组件中使用
<script setup lang="ts">
import { useCounterStore } from '../stores/counter'
const counterStore = useCounterStore()
</script>
<template>
<p>计数:{{ counterStore.count }}</p>
<button @click="counterStore.increment">+1</button>
<button @click="counterStore.reset">重置</button>
</template>
Store 的两种写法
组合式(推荐)
用 ref、computed,更像 Vue 3 Composition API:
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const double = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, double, increment }
})
选项式
用 state、getters、actions:
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
double: (state) => state.count * 2
},
actions: {
increment() {
this.count++
}
}
})
推荐组合式,TypeScript 支持更好。
多组件共享状态
任何组件都可以使用 store,修改会同步到所有使用的地方。
<!-- ComponentA.vue -->
<script setup>
const store = useCounterStore()
store.increment()
</script>
<!-- ComponentB.vue -->
<script setup>
const store = useCounterStore()
console.log(store.count) // 已经 +1 了
</script>
getters
计算属性,类似 computed:
export const useUserStore = defineStore('user', () => {
const firstName = ref('张')
const lastName = ref('三')
const fullName = computed(() => lastName.value + firstName.value)
return { firstName, lastName, fullName }
})
使用:
<script setup>
const userStore = useUserStore()
</script>
<template>
<p>{{ userStore.fullName }}</p>
</template>
actions
Actions 是修改状态的方法,可以是异步的:
export const useUserStore = defineStore('user', () => {
const userInfo = ref(null)
async function fetchUser(id: string) {
const res = await fetch(`/api/user/${id}`)
userInfo.value = await res.json()
}
function updateName(name: string) {
if (userInfo.value) {
userInfo.value.name = name
}
}
return { userInfo, fetchUser, updateName }
})
持久化
浏览器刷新后状态会丢失,需要持久化可以装插件:
pnpm add pinia-plugin-persistedstate
注册:
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
使用:
export const useUserStore = defineStore('user', () => {
const token = ref('')
return { token }
}, {
persist: true // 开启持久化
})
Pinia vs Vuex
| 特性 | Pinia | Vuex |
|---|---|---|
| API | 简洁 | 相对复杂 |
| TypeScript | 原生支持好 | 需要装饰器 |
| 体积 | 稍小 | 稍大 |
| 调试工具 | 支持 | 支持 |
| 文档 | 清晰 | 较复杂 |
Vue 3 项目推荐用 Pinia,更简单、更好维护。
总结
defineStore创建 storeref定义状态,computed定义 getter,function定义 action- 组合式写法更推荐
- 组件中通过
useStore()使用 pinia-plugin-persistedstate可以做持久化
下篇讲组件间通信,包括 props、emit 和 Pinia 的组合使用。
