本文主要记录Vue3状态管理工具Pinia的介绍与使用
集中式管理状态容器,可以实现任意组件之间的通讯
核心:
集中式管理状态容器,可以实现任意组件之间的通讯
核心:
优点:
npm install pinia -S
这里有两种方式建立大仓库:
import {createPinia,PiniaVuePlugin} from "pinia";
let store = createPinia()
app.use(store)
// index.ts
import {createPinia,PiniaVuePlugin} from "pinia";
/**
* 利用createPinia方法创建大仓库(在Vue2中使用PiniaVuePlugin)
* 并对外暴露该仓库
* 在全局引入
*/
let store = createPinia()
export default store
全局引入:
import store from "./store";
app.use(store)
在Vue3中使用createPiniaAPI, Vue2中使用PiniaVuePluginAPI
选择式:
/**
* 选择式API仓库
* defineStore方法定义小仓库,带两个参数
* 1、仓库名称
* 2、仓库配置对象
* defineStore返回一个函数,让组件可以获取到仓库数据
* 存储数据:state
* 需对外暴露方法
*/
import {defineStore} from "pinia";
let userInfoStore = defineStore("info",{
state:()=>{
return {
count: 99,
arr: [1,2,3,4,5,6,7,8,9,10]
}
},
actions: {
//内部没有context上下文对象
//没有commit、没有mutations去修改数据
updateNum(a:number,b:number){
this.count+=(a+b)
}
},
getters: {
total() {
let result:number = this.arr.reduce((prev,next)=>{
return prev+next
},0)
return result
}
}
})
export default userInfoStore
组合式:
/**
* 定义组合式API仓库
* 务必返回一个对象:属性与方法可以提供给组件使用
*/
import {defineStore} from "pinia";
import {computed, reactive} from "vue";
let userTodoStore = defineStore("todo",()=>{
let todos = reactive([{id:1,title:'吃饭'},{id:2,title:'睡觉'}])
let arr = reactive([1,2,3,4,5,6])
const total = computed(()=>{
return arr.reduce((prev,next)=>{
return prev+next
},0)
})
return {
todos,
total,
updateTodo(){
todos.push({id:3,title: '组合式API'})
}
}
})
export default userTodoStore
这里命名也可以通过枚举类来管理名称
export const enum Names {
TEST='TEST'
}
使用:
import {Names} from "../store-name";
import {defineStore} from 'pinia'
export const useTestStore = defineStore(Names.TEST,{
state:()=>{
return {
current:1,
name:'smz'
}
},
getters:{
},
actions:{}
})
修改数据:
import userInfoStore from "../../../store/modules/info";
let infoStore = userInfoStore()
infoStore.count++
import userInfoStore from "../../../store/modules/info";
let infoStore = userInfoStore()
infoStore.$patch({count:222})
import userInfoStore from "../../../store/modules/info";
let infoStore = userInfoStore()
infoStore.updateNum(1,2)
仓库:
actions: {
//内部没有context上下文对象
//没有commit、没有mutations去修改数据
updateNum(a:number,b:number){
this.count+=(a+b)
}
},
注:在方法内部要用this,this指向仓库对象
修改数据:
import userTodoStore from "../../../store/modules/todo";
let todoStore = userTodoStore()
todoStore.todos[0].title = '喝水'
const total = computed(()=>{
return arr.reduce((prev,next)=>{
return prev+next
},0)
})
updateTodo(){
todos.push({id:3,title: '组合式API'})
}
注:在方法内部要用this,this指向仓库对象
修改state中的数据有以下五种方式:
修改值的方法:
Test.current++
Test.$patch({current:888,name:'smz2'})
Test.$patch((state)=>{state.current = 999})
4.使用函数上自带的$state方法
该方法需要修改整个对象
Test.$state = {current:2000,name: "smz3"}
actions:{setCurrent(number){this.current = number}}
Test.setCurrent(28888)
state解构
const {current,name} = Test
这样解构出来的值是不具备数据响应式的
需要使用 storeToRefs 包裹 和toRefs效果一致
import {storeToRefs} from 'pinia'
const {current,name} = storeToRefs(Test)
actions可以用同步也可以使用异步
let result:User = {
name: 'Pinia'
}
// actions内
setUser(){
this.user = result
},
const Login = ():Promise<User> =>{
return new Promise(resolve => {
setTimeout(()=>{
resolve({
name:"1234"
})
},2000)
})
}
// actions内
async setUser2(){
this.user =await Login()
}
actions内的方法是可以相互调用的
setCurrent(number){
this.current = number
},
setUser(){
this.user = result
this.setCurrent(666)
},
用来修饰值,这里有两种写法,在其中是可以相互调用的
getters:{
newName():string{
return `name: ${this.name}`
},
newName2():string{
return this.newName()
}
},
重新初始化仓库,直接使用就可以将仓库初始化成原始值
Test.$reset()
响应 store 变化,该方法会监听state中的数据变化,与watch有相同的功能,比起普通的 watch(),使用 $subscribe() 的好处是 subscriptions 在 patch 后只触发一次
可以设置detached:true 来控制组件被销毁时也能继续监听,还包括了其他一些配置项
Test.$subscribe((args,state)=>{
console.log(args)
console.log(state)
},{
detached:true,
deep:true,
flush:'post'
})
监听action,在一个action即将被调用时,将触发该方法,回调接收一个对象, 其包含被调用 action 的所有相关信息:
除此之外,它会接收两个函数, 允许在 action 完成或失败时执行的回调。
Test.$onAction(({ after, onError }) => {
// 你可以在这里创建所有钩子之间的共享变量,
// 同时设置侦听器并清理它们。
after((resolvedValue) => {
// 可以用来清理副作用
// `resolvedValue` 是 action 返回的值,
// 如果是一个 Promise,它将是已经 resolved 的值
})
onError((error) => {
// 可以用于向上传递错误
})
},true)
它还会返回一个用来删除回调的函数。 请注意,当在组件内调用 store.$onAction() 时,除非 detached 被设置为 true, 否则当组件被卸载时,它将被自动清理掉。
在Pinia中,数据在页面刷新后将被重新初始化,所以需要一个持久化插件来解决这个问题,原理都是将其存入localStorage中
使用现成的持久化插件:
pinia-plugin-persistedstate
pnpm i pinia-plugin-persistedstate
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
const useTestStore = defineStore("Test",{
// 开启数据持久化
persist: true
});
一些其他配置:
import { defineStore } from 'pinia'
export const useStore = defineStore('main', s{
state: () => {
return {
someState: 'hello pinia',
nested: {
data: 'nested pinia',
},
}
},
// 所有数据持久化
// persist: true,
// 持久化存储插件其他配置
persist: {
// 修改存储中使用的键名称,默认为当前 Store的 id
key: 'storekey',
// 修改为 sessionStorage,默认为 localStorage
storage: window.sessionStorage,
// 部分持久化状态的点符号路径数组,[]意味着没有状态被持久化(默认为undefined,持久化整个状态)
paths: ['nested.data'],
},
})
PInia持久化参考了文章:Pinia的使用以及数据持久化
Pinia相对于VueX来说,简化了API的使用,支持TS,让学习成本大大降低。