前言
- 支持vue2和vue3
- 安装: npm i pinia
相比于vuex
- Vuex
- 优点
- 支持调试功能,如时间旅行和编辑
- 适用于大规模和高复杂性的Vue.js项目
- 缺点
- 从 Vue3 开始,getter的结果不会像计算属性那样被缓存起来
- Vuex4 有一些与类型安全相关的问题
- 优点
- Pinia
- 优点
- 体积更小
- 能更好的支持ts
- 没有mutation,全都放在 action 中了
- action 被调度为常规的函数调用,而不是使用 dispatch方法 或 MapAction 辅助函数
- 支持多个Store
- 支持 Vue devtools、SSR 和 webpack 代码拆分
- 缺点
- 不支持时间旅行和编辑等调试功能
- 优点
基本使用
- 在main.ts中注册
import { createPinia } from 'pinia';
app.use(createPinia());
- 在store/index.ts管理状态
import { defineStore } from 'pinia';
// 返回一个函数
export const useMainStore = defineStore({
// id必须在所有 Store 中唯一
id: "globalState",
// 必须是箭头函数: 为了更好的使用ts
state: () => ({
count: 1
}),
});
- 在组件中使用方式一
<template>
<div>
// 使用state数据
{{ mainStore.count }}
</div>
</template>
<script>
// 导入 Store
import { useMainStore } from '@/store/index.ts';
export default {
setup() {
// 调用Store函数,获得Store实例
const mainStore = useMainStore();
return {
mainStore
}
}
}
</script>
- 在组件中使用方式二: 使用storeToRefs解构
<template>
<div>
// 使用state数据
{{ count }}
</div>
</template>
<script>
import { storeToRefs } from 'pinia';
import { useMainStore } from '@/store/index.ts';
export default {
setup() {
const mainStore = useMainStore();
// const { count } = mainStore // 非响应式
// js中使用: count.value
const { count } = storeToRefs(mainStore) // 响应式
return {
count
}
}
}
</script>
修改数据(action)
export const useMainStore = defineStore({
id: "globalState",
state: () => ({
count: 1,
foo: 'hi',
arr: [1, 2, 3]
}),
// 同步异步都可以写在这里
action: {
changeState(num) {
this.count++
this.foo = 'hello'
this.arr.push(num)
// this.$patch({})
// this.$patch(state => {})
}
}
});
setup() {
const mainStore = useMainStore();
const { count, foo, arr } = storeToRefs(mainStore)
const handleChangeState = () => {
// 方式一: 多次修改,性能较差
mainStore.count++
mainStore.foo = 'hello'
mainStore.arr.push(4)
// 方式二: 批量更新
mainStore.$patch({
count: mainStore.count + 1
foo: 'hello',
arr: [...mainStore.arr, 4]
})
// 方式三: 更好的批量更新方式
mainStore.$patch(state => {
state.count++
state.foo = 'hello'
state.arr.push(4)
})
// 方式四: action中修改
mainStore.changeState(4)
}
return {
count,
foo,
arr
}
}
getters
类似于计算属性,与vuex中的用法一致
export const useMainStore = defineStore({
id: "globalState",
state: () => ({
count: 1,
}),
getters: {
count10(state) {
// return this.count + 10 // 也可以直接用this
return state.count + 10
}
}
});
模块化
-
store/user.js
import { defineStore } from 'pinia' const useUserStore = defineStore('user', { state: () => { name: 'zs', age: 100, }, }) export default useUserStore -
store/index.js
import useUserStore from './user' import useCounterStore from './counter' // 统一导出useStore方法 export default function useStore() { return { user: useUserStore(), counter: useCounterStore(), } } -
在组件中使用
import { storeToRefs } from 'pinia' import useStore from './store' const { counter } = useStore() const { count, double } = storeToRefs(counter)
数据持久化
-
安装: npm i pinia-plugin-persistedstate
-
main.ts中配置插件
import { createPinia } from 'pinia' import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' const pinia = createPinia() pinia.use(piniaPluginPersistedstate) app.use(pinia) -
数据持久化
import { defineStore } from 'pinia' export const useUserStore = defineStore('main', { state: () => { someState: 'hello pinia', nested: { data: 'nested pinia', }, }, // 所有数据持久化 // persist: true, persist: { // 修改存储中使用的键名称,默认为当前 store 的 id key: 'storekey', // 修改为存储方式,默认为 localStorage storage: window.sessionStorage, // 按需持久化部分数据,[]意味着没有状态被持久化(默认为undefined,持久化整个状态) paths: ['nested.data'], }, })
参考
- 鹏周同学: 抛弃 Vuex,使用 Pinia
- 搬砖小能手丶: Pinia的使用以及数据持久化