状态管理容器Pinia
本文主要记录Vue3状态管理工具Pinia的介绍与使用,Pinia相对于VueX来说,简化了API的使用,支持TS,让学习成本大大降低。
文章目录
前言
本文主要记录Vue3状态管理工具Pinia的介绍与使用
一、集中式状态管理容器
1、VueX
集中式管理状态容器,可以实现任意组件之间的通讯
核心:
- state 存储数据
- mutations 唯一修改数据
- actions 处理异步、处理业务
- getters 计算属性
- modules 模块式开发
2、Pinia
集中式管理状态容器,可以实现任意组件之间的通讯
核心:
- state 存储数据
- actions 修改数据、处理异步、处理业务
- getters 计算属性
优点:
- 完全支持TS,在JS中也提供自动补全
- 体积小
- 去除了 VeuX 的 mutations 和 modules
- actions 可同步也可异步
- 每个store都是独立的仓库,在打包时可拆分每个仓库
- 极致轻量化
- 自动加载store
- 支持Vue2和Vue3
- 可拓展性,可以通过本地存储等方式扩展PInia
创建步骤:
- 安装Pinia
npm install pinia -S
- 建立大仓库
这里有两种方式建立大仓库:
- 直接在Mian.ts文件中建立
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
- 建立小仓库
- 利用defineStoreAPI创建小仓库
这里创建小仓库,必须传一个唯一名称,用来创建唯一的仓库,也就对应了他所说的模块化了吧。这里小仓库可以选择一个小仓库对应一个文件,也可以多个小仓库组成一个功能模块在一个文件中。
这里也分为选择式和组合式两种
选择式:
/**
* 选择式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:{}
})
用法:
1、选择式
修改数据:
- 使用返回的函数直接修改其属性
import userInfoStore from "../../../store/modules/info";
let infoStore = userInfoStore()
infoStore.count++
- 使用返回函数上的$patch方法
import userInfoStore from "../../../store/modules/info";
let infoStore = userInfoStore()
infoStore.$patch({count:222})
- 使用自定义方法,在actions中定义方法,可传参
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指向仓库对象
2、组合式
修改数据:
- 使用返回的函数直接修改其属性
import userTodoStore from "../../../store/modules/todo";
let todoStore = userTodoStore()
todoStore.todos[0].title = '喝水'
- 使用computed计算属性,将计算值返回就能获取
const total = computed(()=>{
return arr.reduce((prev,next)=>{
return prev+next
},0)
})
- 使用自定义方法,在return中定义方法,可传参
updateTodo(){
todos.push({id:3,title: '组合式API'})
}
注:在方法内部要用this,this指向仓库对象
二、state
修改值
修改state中的数据有以下五种方式:
修改值的方法:
- 直接修改
Test.current++
- 使用函数上自带的$patch方法
Test.$patch({current:888,name:'smz2'})
- 以$patch箭头函数形式
这里的state就是仓库里的state
Test.$patch((state)=>{state.current = 999})
4.使用函数上自带的$state方法
该方法需要修改整个对象
Test.$state = {current:2000,name: "smz3"}
- 在actions内定义方法,用this直接修改值
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 - getters
actions
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
用来修饰值,这里有两种写法,在其中是可以相互调用的
getters:{
newName():string{
return `name: ${this.name}`
},
newName2():string{
return this.newName()
}
},
四、API
$reset
重新初始化仓库,直接使用就可以将仓库初始化成原始值
Test.$reset()
$subscribe
响应 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'
})
$onAction
监听action,在一个action即将被调用时,将触发该方法,回调接收一个对象, 其包含被调用 action 的所有相关信息:
- store: 被调用的 store
- name: action 的名称
- args: 传递给 action 的参数
除此之外,它会接收两个函数, 允许在 action 完成或失败时执行的回调。
Test.$onAction(({ after, onError }) => {
// 你可以在这里创建所有钩子之间的共享变量,
// 同时设置侦听器并清理它们。
after((resolvedValue) => {
// 可以用来清理副作用
// `resolvedValue` 是 action 返回的值,
// 如果是一个 Promise,它将是已经 resolved 的值
})
onError((error) => {
// 可以用于向上传递错误
})
},true)
它还会返回一个用来删除回调的函数。 请注意,当在组件内调用 store.$onAction() 时,除非 detached 被设置为 true, 否则当组件被卸载时,它将被自动清理掉。
五、Pinia插件
在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,让学习成本大大降低。
更多推荐
所有评论(0)