Pinia 全局状态管理工具

全局状态管理工具,比 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')