全局状态管理工具,比 vuex 更轻量,有完整的 ts 支持,更适合 vue3
和 vuex 相比,去除了 mutations, 保留了 state 、 getters、 actions。 actions 支持同步和异步
代码扁平化没有嵌套模块,只有 store 的概念, store 可以自由使用,每一个store 都是独立的
无需手动添加 store ,一旦创建会自动添加
安装
yarn add pinia -S
使用
import { createApp } from 'vue'
import App from './App.vue'
// vue3导入,如果是 vue2 还需要额外导入依赖,具体看文档
import { createPinia } from 'pinia'
const store = createPinia()
createApp(App).use(store).mount('#app')
import { defineStore } from 'pinia'
import { Names } from './store-name' // 枚举对象ID
// 导出的是个hook, 这里的第一个值 name 很重要,后面写插件保存到本地会根据 id 来取
export const useStore = defineStore(Names.name, {
state: ()=>{
return {
name: 'chon'
age: 12
}
},
// 类似于computed 修饰一些值,没有缓存
getters: {
}
// 类似于 methods 可以做同步异步 提交 state
actions: {
}
})
import { useStore } from './store'
const store = useStore()
<div>{{ store.name }}</div>
修改 state 状态的几种方式
1 - 直接使用实例的 store 去修改值,但是这样违背了单向数据流,不推荐
store.name = 'xxx'
2 - 使用实例 store 里的 $patch 方法,里面包含工厂函数,方便处理逻辑,参数为 state
store.$patch((state) => {
if(xxx) {
state.name = '...'
}
})
3 - 使用实例 store 里的 $state 方法,相当于重写覆盖整个对象
store.$state = {
name: 'xxx'
}
5 - 使用 actions 修改,主要不要在 actions 里使用箭头函数,因为 this 指向会出问题,默认指向state
// store.ts
actions: {
setName() {
this.name = 'xxx'
}
}
// 组件
store.setName()
直接从实例解构出来的参数和 reactive 一样是不具备响应式的,可以导入 pinia 里的 storeToRefs API 像 toRefs 一样包着 store 就可以了
API
$reset - 把state 恢复到默认初始值
$subscribe - 监听值的变化触发
Pinia 插件
pinia 和 vuex 一样都有页面刷新状态丢失的缺陷,我们可以通过自己封装一个插件保存到本地 localstorage 里
// main.ts
import { createPinia, PiniaPluginContext } from 'pinia'
import { createApp, toRaw } from 'vue'
import App from './App.vue'
type KEY_ID = {
key?: string
}
const setStorage = (key: string, value: any) => {
localStorage.setItem(key, JSON.stringify(value))
}
const getStorage = (key: string) => {
return localStorage.getItem(key) ? JSON.parse(localStorage.getItem(key) as string) : {}
}
// 自己封装插件把 pinia 保存到本地
const piniaPlugin = (keyID: KEY_ID) => {
// 使用函数柯里化的模式, context 就是当前整个 store 对象
return (context: PiniaPluginContext) => {
const { store } = context
// 若本地有store对象 取出本地的 store
const data = getStorage(`${keyID.key ?? 'piniaObj'}-${store.$id}`)
// 当 store 发生变化时存入本地
store.$subscribe(() => {
setStorage(`${keyID.key ?? 'piniaObj'}-${store.$id}`, toRaw(store.$state))
})
return {
...data,
}
}
}
const store = createPinia()
store.use(
piniaPlugin({
key: 'pinia',
})
)
createApp(App).use(store).mount('#app')