Pinia基本介绍
什么是Pinia
Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。
- 状态管理库
Store是一个保存状态、业务逻辑 的实体,每个组件都可以读取、写入它。 - 它有三个概念:state、getter、action
-
state为各个组件需要共享的状态,相当于组件中的datagetter为状态代理(在获取状态时对状态进行变更),相当于组件中的computedaction为对状态的一系列操作,相当于组件中的methods
Pinia与组件hooks的区别
pinia就是将多个组件需要共享的状态抽取出来,实现跨组件和页面共享状态。它与hooks的区别在于,hooks是对功能模块的封装和拆分,让其有更高的复用性,目标是解耦和复用功能模块,而pinia的目标是共享和维护状态
搭建 pinia 环境
- 下载pinia到项目
npm install pinia - 注册使用pinia
import { createApp } from "vue";
// 导入根组件
import App from './App.vue'
// 导入pinia
import { createPinia } from "pinia";
// 创建pinia
const pinia = createPinia()
// 创建根组件
const app = createApp(App)
// 注册pinia
app.use(pinia)
app.mount('#app')
此时开发者工具中已经有了pinia选项表示pinia已经安装到项目中
Pinia的基本操作
存储状态
存储sum,num变量状态:src/store/count.ts
// 导入store
import { defineStore } from "pinia";
export const useCountStore = defineStore('count', {
// 动作
actions: {
// 加
increment(value: number) {
// 进行逻辑判断,若sum值小于10再进行加
if (this.sum < 10) this.sum += value;
},
// 减
decrement(value: number) {
if (this.sum > 1) {
this.sum -= value
}
}
},
// 状态
state() {
return {
sum: 6,
num: 0
}
},
// 计算
getters: {}
})
获取状态
<script setup lang="ts" name="Count">
// 导入sum状态管理构造器
import { useCountStore } from '@/store/count'
// 创建状态管理器
const countStore = useCountStore()
// 第一种获取方式,直接获取方式
let sum = countStore.sum
// 第二种获取方式,通过$state获取
let sum = countStore.$state.sum
</script>
修改状态
第一种修改方式,直接修改
countStore.sum = 666
第二种修改方式:批量修改
countStore.$patch({
sum:999,
num:1
})
第三种修改方式:借助action修改(action中可以编写一些业务逻辑)
组件中调用action即可
<script setup lang="ts" name="Count">
// 导入sum状态管理构造器
import { useCountStore } from '@/store/count'
// 创建状态管理器
const countStore = useCountStore()
// 调用对应action
countStore.incrementOdd(n.value)
</script>
pinia的进阶操作
storeToRefs
当需要获取的状态是响应式的时候可以借助storeToRefs将store中的数据转为ref对象,方便在模板中使用。
<template>
<div class="count">
<h2>当前求和为:{{sum}}</h2>
</div>
</template>
<script setup lang="ts" name="Count">
import { useCountStore } from '@/store/count'
/* 引入storeToRefs */
import { storeToRefs } from 'pinia'
/* 得到countStore */
const countStore = useCountStore()
/* 使用storeToRefs转换countStore,随后解构 */
const {sum} = storeToRefs(countStore)
</script>
提示:pinia提供的storeToRefs只会将状态数据转换为响应式,而Vue的toRefs会转换store全部数据为响应式。所以不要使用Vue的toRefs来将状态中的数据进行响应式转换,代价太大,如下图
let sotre = toRefs(countStore)
getters
当state中的数据,需要经过处理后再使用时,可以使用getters配置。
state() {
return {
sum: 6,
num: 0
}
},
// 计算
getters: {
mutipleSum(state) {
return state.sum * 10
},
decoratorNum(state): string {
// this就是state
return "点击次数为:" + this.num
}
}
获取状态
// 导入sum状态管理构造器
import { useCountStore } from '@/store/count'
// 导入pinia的状态转换器
import { storeToRefs } from 'pinia'
// 创建状态管理器
const countStore = useCountStore()
// 将状态转换为响应式数据
let { sum, mutipleSum, decoratorNum } = storeToRefs(countStore)
$subscribe
state保存着talkList这一状态
state() {
return {
talkList: JSON.parse(localStorage.getItem("talkList") as string) || []
}
},
通过 store 的 $subscribe() 方法侦听 state 及其变化,当store中的状态发生变化的时候会触发回调函数。
talkStore.$subscribe((mutate,state)=>{
localStorage.setItem('talk',JSON.stringify(talkList.value))
})
提示:$subscribe可以解决刷新丢失状态的问题
store组合式写法
import {defineStore} from 'pinia'
import axios from 'axios'
import {nanoid} from 'nanoid'
import {reactive} from 'vue'
export const useTalkStore = defineStore('talk',()=>{
// talkList就是state
const talkList = reactive(
JSON.parse(localStorage.getItem('talkList') as string) || []
)
// getATalk函数相当于action
async function getATalk(){
// 发请求,下面这行的写法是:连续解构赋值+重命名
let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
// 把请求回来的字符串,包装成一个对象
let obj = {id:nanoid(),title}
// 放到数组中
talkList.unshift(obj)
}
// 一定要交出去
return {talkList,getATalk}
})