Vue3.js store 状态管理库 pinia,Composition API 使用更友好
Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态。同时支持 vue2 和 vue3。
安装
yarn add pinia
使用
创建一个 pinia 并将其传递给应用程序
// main.ts
import { createPinia } from 'pinia'
createApp(App).use(createPinia()).use(router).mount('#app')
State
定义一个 ‘Counter’ store
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('Counter', {
state: () => {
return {
count: 0
}
}
})
使用 stroe
<script lang="ts" setup>
import { useCounterStore } from '../store/counter'
const counterStore = useCounterStore()
</script>
<template>
<div class="pinia-box">
{{ counterStore.count }}
</div>
</template>
<style lang="less" scoped>
.pinia-box {
padding: 20px;
}
</style>
与计算属性 computed
import { computed } from 'vue'
const doubleCounter = computed(() => counterStore.count * 2)
改变 store
const increment = (): void => {
counterStore.count++
}
const decrement = (): void => {
counterStore.count--
}
还可用使用 $patch 改变 store
const increment = (): void => {
counterStore.$patch({
count: counterStore.count + 2
})
}
替换 store
const replaceStore = (): void => {
counterStore.$state = {
count: 100
}
}
订阅 store
可以通过 store 的 $subscribe()
方法查看状态及其变化,类似于 Vuex 的 subscribe 方法。
counterStore.$subscribe((mutation, state) => {
console.log(mutation.type, state)
})
注意:
默认情况下,state subscriptions 绑定到添加它们的组件(如果 store 位于组件的 setup()
中)。 意思是,当组件被卸载时,它们将被自动删除。 如果要在卸载组件后保留它们,请将 { detached: true }
作为第二个参数传递给 detach 当前组件的 state subscription:
counterStore.$subscribe(function() {
// 此订阅将在组件卸载后保留
}, { detached: true })
Getters
Getter 完全等同于 Store 状态的 计算值。 它们可以用 defineStore()
中的 getters
属性定义。
getter 依赖状态
export const useCounterStore = defineStore('Counter', {
state: () => {
return {
count: 0
}
},
getters: {
doubleCount: (state) => state.count * 2
}
})
getter 依赖另外一个 getter
与计算属性一样,您可以组合多个 getter。 通过 this
访问任何其他 getter。
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('Counter', {
state: () => {
return {
count: 0
}
},
getters: {
doubleCount: (state): number => state.count * 2,
doubleCountPlusOne: (state): number => (state as any).doubleCount + 1
}
})
getter 参数传入
请注意,在执行此操作时,getter 不再缓存,它们只是您调用的函数。
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('Counter', {
state: () => {
return {
count: 0
}
},
getters: {
multipleCount: (state) => {
return (coefficient: number) => state.count * coefficient
}
}
})
访问其它 store 中的 getter
import { defineStore } from 'pinia'
import { useUserStore } from './user'
export const useCounterStore = defineStore('Counter', {
state: () => {
return {
count: 0
}
},
getters: {
loginUserName: (state) => {
return useUserStore().user.name
}
}
})
Actions
Actions 相当于组件中的 methods。 它们可以使用 defineStore()
中的 actions
属性定义,并且它们非常适合定义业务逻辑:
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('Counter', {
state: () => {
return {
count: 0
}
},
actions: {
increment() {
this.count++
},
decrement() {
this.count--
}
}
})
注意:这里的 actions 与 vuex 中的 actions 不等同,这里不仅仅是异步任务,同步任务也在这里。Pinia 没有 mutation 方法。
异步 actions
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
user: {
name: '游客'
},
}),
getters: {
isLoggedIn: (state) => !!state.user,
},
actions: {
// 登录
async login(userName, password) {
const result = await api.post({ userName, password})
this.user = result
},
// 登出
async logout() {
this.$reset()
},
},
})
访问其它 store 操作,与 getter 一样。
Plugins
使用 pinia.use()
将插件添加到 pinia 实例中。 最简单的例子是通过返回一个对象为所有Store添加一个静态属性:
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'
function AuthPiniaPlugin() {
return {
isAuth: true
}
}
const pinia = createPinia()
pinia.use(AuthPiniaPlugin)
createApp(App).use(pinia).use(router).mount('#app')
添加外部属性,与 router 结合
import { markRaw } from 'vue'
import { router } from './router'
pinia.use(({ store }) => {
store.router = markRaw(router)
})
在插件中调用 $subscribe
您也可以在插件中使用 store.$subscribe 和 store.$onAction :
pinia.use(({ store }) => {
store.$subscribe(() => {
// 在存储变化的时候执行
})
store.$onAction(() => {
// 在 action 的时候执行
})
})
Pinia 与 Vuex 区别
Vuex 和 Pinia 都是用于管理 Vue.js 应用程序状态的官方状态管理库。它们都提供了一种集中式存储来管理组件的状态,并且都可以在组件之间共享状态。
Vuex | Pinia | |
---|---|---|
相同点 | – 都是官方支持的状态管理库 – 都提供了一种集中式存储来管理组件的状态 – 都可以在组件之间共享状态 | – 都是官方支持的状态管理库 – 都提供了一种集中式存储来管理组件的状态 – 都可以在组件之间共享状态 |
不同点 | – Vuex 是专门为 Vue.js 设计的,而 Pinia 是为现代化的 Vue.js 应用程序设计的 – Vuex 使用 ES6 类语法,而 Pinia 使用 ES6 函数语法 – Vuex 提供了更多的功能,例如模块、插件等,而 Pinia 则更注重简单性和易用性 – Vuex 的学习曲线较陡峭,需要掌握一些概念和模式,而 Pinia 则更加直观和易于上手 | – Vuex 是专门为 Vue.js 设计的,而 Pinia 是为现代化的 Vue.js 应用程序设计的 – Vuex 使用 ES6 类语法,而 Pinia 使用 ES6 函数语法 – Vuex 提供了更多的功能,例如模块、插件等,而 Pinia 则更注重简单性和易用性 – Vuex 的学习曲线较陡峭,需要掌握一些概念和模式,而 Pinia 则更加直观和易于上手 |