Pinia 概念
是 Vue 的存储库,它允许您跨组件/页面共享状态。 Vue官方推荐状态库
Pinia 的优点
pinia 符合直觉,易于学习。
pinia 是轻量级状态管理工具,大小只有1KB.
pinia 模块化设计,方便拆分。
pinia 没有 mutations,直接在 actions 中操作 state,通过 this.xxx 访问响应的状态,尽管可 以直接操作 state,但是还是推荐在 actions 中操作,保证状态不被意外的改变。
store 的 action 被调度为常规的函数调用,而不是使用 dispatch 方法或者是 MapAction 辅助函数,这是在 Vuex 中很常见的。
支持多个 store。
支持 Vue devtools、SSR、webpack 代码拆分。
什么时候使用Store
存储应该包含可以在整个应用程序中访问的数据。这包括在许多地方使用的数据
避免可以托管在组件的数据使用Store
创建项目(vite + vue3 + pinia):
pnpm create vite
cd project
pnpm i
pnpm i pinia
pnpm run dev
如果您的应用使用 Vue 2,您还需要安装组合 API:@vue/composition-api
创建一个pinia(根存储):
如果是 vue 3.2 + pinia 2.1.4版本,可能由以下报错:
import { hasInjectionContext,inject,toRaw,watch,…
是由于版本不兼容导致的
在package.json升级vue到3.3.4版本即可
基本使用
(1)创建一个 pinia(根存储)并将其传递给应用程序
修改main.js
import { createPinia } from 'pinia'
createApp(App).use(pinia).mount('#app')
(2) src下新建store文件夹,然后在store下创建counter.js文件
defineStore参数:
第一个参数是唯一的 id, 标志着一个命名空间
第二个参数是一个对象, 有三个模块: state, getters,actions
const useCounter = defineStore("counter", {
state () {
return {
count: 66,
}
},
getters: {
},
actions: {
}
})
// 返回函数统一使用useXXX命名
export default useCounter;
(3) 在组件中使用:
修改,定义组件
<template>
<div>展示pinia的counter的counter值: {{ counterStore.count }}</div>
<div>解构出来的pinia的counter的count值: {{ count1 }}</div>
<div>storeToRefs: {{ count2 }}</div>
<button @click="addCount">count+1</button>
</template>
<script setup>
import useCounter from '../stores/counter'
import {storeToRefs} from 'pinia'
const counterStore = useCounter()
const {count1} = counterStore // 解构得到的失去响应式
const {count2} = storeToRefs(counterStore) // 不会失去响应式
function addCount() {
counterStore.count++
}
修改App.vue,使用组件
<template>
<Counter1/>
</template>
<script setup>
import Counter1 from './components/Counter1.vue'
</script>
(4) Store获取后不能解构, 否则失去响应式
const {count} = counterStore
解决方案:
提供了函数storeToRefs解决,作用就是把结构的数据使用ref做代理
import {storeToRefs} from 'pinia'
const counterStore = useCounter()
const {count} = storeToRefs(counterStore)
(5)修改state的数据
重新新建一个user模块store/user.js
import {defineStore} from 'pinia'
const useUser = defineStore("user", {
state:() => ({
name: "cq",
age: 17
})
})
export default useUser
新建组件 ChangeVaule.vue:
有几种修改state的方法
<template>
<div>
<h2>名字是:{{ name }}</h2>
<h2>年龄是: {{ age }}</h2>
<button @click="updateStore">修改Store数据</button>
<button @click="resetStore">重置Store数据</button>
</div>
</template>
<script setup>
import useUser from '../stores/user'
import { storeToRefs } from 'pinia';
const userStore = useUser()
const {name, age} = storeToRefs(userStore)
function updateStore() {
// 1. 一个个修改状态
// userStore.name = "川崎"
// userStore.age = 19
// 2. $patch一次改变多个状态
userStore.$patch({
name: "川川",
age: 18
})
// 3. $state(替换, 基本不用)
}
function resetStore() {
// 4. $reset()是重置state数据的
userStore.$reset()
}
</script>
getters的使用:
getters类似于vue的计算属性,可以对已有的数据进行修饰。不管调用多少次,getters中的函数只会执行一次,而且会缓存
(1) 最基本使用
在store/counter.js添加getters:
const useCounter = defineStore("counter", {
state:() => ({
count:66,
})
getters: {
doubleCount(state) {
doubleCount(state) {
return state.count * 2
}
}
}
})
export default useCounter
在组件中使用:
<div>
<h1>getters使用: </h1>
<h2>doubleCount:{{counterStore.doubleCount}}</h2>
</div>
(2)一个getter引入另一个getter
counter模块:
getters: {
doubleCount(state) {
return state.count * 2
},
doubleCountAddTwo() {
console.log(this)
return this.doubleCount + 2
}
}
组件中使用:
<div>
<h2>doubleCount: {{counterStore.doubleCount}}</h2>
<h2>doubleCountAddTwo: {{counterStore.doubleCountAddTwo}}</h2>
</div>
运行且看看getters的this打印:
this中有两个getters
(3) getters中使用别的store数据
在counter模块中拿user模块store数据
count模块的getters添加:
import useUser from "./user"
...
showMessage(state){
console.log(state);
console.log(this)
//获取user信息,拿到useUser模块
const userStore = useUser()
//拼接信息
return `name:${userStore.name}--count:${state.count}`
}
在组件中使用:
<div>
<h2>showMessage:{{counterStore.showMessage}}</h2>
</div>
结果:
实现了counter模块中拿到了user模块的数据
actions的使用:
actions可以处理同步,也可以处理异步,类似于methods
(1) 同步使用:
counter模块使用:
在actions定义两个函数一个加1函数,一个加Num函数
actions: {
increment(state) {
console.log(state)
console.log(this)
this.count++
},
incrementNum(num) {
this.count += num
},
组件中使用:
<h2>展示pinia的counter的counter值: {{ counterStore.count }}</h2>
<h2>doubleCountAddTwo:{{ counterStore.doubleCountAddTwo }}</h2>
<button @click="incrementOne">count+1</button>
<button @click="incrementNum">count+20</button>
点击count+1 ⇒ 加一
点击count+20 ⇒ 加二十
(2) 异步操作使用
在actions处理异步的时候,异步是与async和await连用
在actions中添加:
// 异步操作
async getData() {
const res =await new Promise((resolve, reject) => {
setTimeout(() => {
resolve([11,22,33,44])
}, 2000)
})
this.list = res
return "ok"
}
新建组件AsyncChangeData.vue:
<template>
<!-- 遍历store的数据 -->
<div v-for="item in counterStore.list">{{ item }}</div>
</template>
<script setup>
import useCounter from '../stores/counter'
const counterStore = useCounter()
counterStore.getData().then(res =>{
console.log("成功",res);
})
</script>
可以看到异步数据延迟显示
数据持久化:
(1) 添加库:
npm i pinia-plugin-persist
(2) 在store中添加:
persist: {
enabled: true, // 开启缓存 默认会存储在本地localstorage
storage: sessionStorage, // 缓存使用方式
paths:[] // 需要缓存键
},
可以看到session中存储的信息
完