我们都知道在vue2项目里搭配状态管理vuex3XX使用,效果极好的。
虽然在vue3项目里,vuex4XX仍能发挥余热,但由于缺乏对于ts的支持,使得类型推断陷入僵局。
所以在vue3+ts的项目里,vuex渐被舍弃,pinia取而代之。(尤雨溪亦力荐之)pinia官网
下面是在vue3 + ts 项目里如何使用 pinia 步骤
这里是如何从零开始由vite构建vue3+ts项目的流程介绍
1 下载 pinia 插件
npm i pinia
2 引入和使用插件
main.ts
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import elementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// ① 引入createPinia方法从pinia
import { createPinia } from 'pinia'
// ② 拿到pinia实例
const pinia = createPinia()
const app = createApp(App)
//使用pinia
app.use(router).use(elementPlus).use(pinia).mount('#app')
3 创建store/home.ts状态管理文件来管理对应页面(home.vue)
store/home.ts
// 每个状态管理文件都要引入此方法
import { defineStore } from 'pinia'
// 官方建议取名遵从 useXXXStore 形式
// 'home' 为当前store的唯一标识 类似ID
// 取名建议与文件名称一致 便于记忆和管理
// pinia舍弃了冗长的mutations属性
// 以下是pinia的一种写法 因与vuex相似 便于学习和记忆
export const useHomeStore = defineStore('home',{
state:()=>{
return{
num:0
}
},
//state也可写成这样
// state:()=>({
// num:0
// }),
actions:{
changeNum(){
//这里可以使用this去拿到state里定义的变量
this.num ++
}
},
getters:{
// 这里取名不可与state里的变量一致 所以取名getNum
getNum:state=>state.num
}
})
4 在对应页面组件home.vue里使用状态管理文件home.ts
home.vue
<template>
<div class="c">this is home page</div>
<div class="c">
<p>使用pinia直接改变变量</p>
<!-- 3 解构赋值后直接在template模板里调用变量和方法 -->
<p>{{ num }}</p>
<button @click="changeNum">点击递增</button>
</div>
</template>
<script lang="ts" setup>
import { toRefs } from 'vue'
// 1 引入
import { useHomeStore } from "../store/home";
// 2 拿到实例
const homeStore = useHomeStore();
// 3 解构里面的变量和方法 toRefs作用是让解构出来的变量具有响应性
const { num,changeNum } = toRefs(homeStore);
</script>
<style scoped>
.c {
width: 80%;
padding: 20px;
margin: 0 auto;
border: 1px solid red;
}
.c>p>span{
color:coral;
}
</style>
静态展示效果:
点击按钮改变变量效果:
如果像这样频繁改变变量 官方建议使用 $patch 方法 (官方优化加持)
具体操作如下
home.vue
<template>
<div class="c">this is home page</div>
<div class="c">
<p>使用pinia直接改变变量</p>
<!-- 3 不解构赋值 在template模板里的写法 -->
<p>{{ homeStore.num }}</p>
<button @click="changeNum">点击递增</button>
</div>
</template>
<script lang="ts" setup>
// 1 引入
import { useHomeStore } from "../store/home";
// 2 拿到实例
const homeStore = useHomeStore();
// 频繁改变homeStore里面的变量 建议使用$patch方法
// 一 $patch的对象式写法
// const changeNum = ()=>{
// homeStore.$patch({
// num: ++ homeStore.num
// })
// }
// 二 $patch的函数式写法
const changeNum = ()=>{
// 这里的state就是home.ts里的state
homeStore.$patch((state)=>{
state.num ++
})
}
</script>
<style scoped>
.c {
width: 80%;
padding: 20px;
margin: 0 auto;
border: 1px solid red;
}
.c>p>span{
color:coral;
}
</style>
效果:
除了以上定义变量后 让变量自身变化的外 我们也可以在actions里请求接口数据赋值变量
如下
home.ts
// 每个状态管理文件都要引入此方法
import { defineStore } from 'pinia'
//引入接口
import { httpPost } from '../request/api'
// 官方建议取名遵从 useXXXStore 形式
// 'home' 为当前store的唯一标识 类似ID
// 取名建议与文件名称一致 便于记忆和管理
// pinia舍弃了冗长的mutations属性
// 以下是pinia的一种写法 因与vuex相似 便于学习和记忆
export const useHomeStore = defineStore('home',{
state:()=>{
return{
num:0,
token:''
}
},
//state也可写成这样
// state:()=>({
// num:0
// }),
actions:{
changeNum(){
//这里可以使用this去拿到state里定义的变量 下面同理
this.num ++
},
changeToken(){
// ts 实在学的不咋地 这里就先any了
httpPost().then((res:any)=>{
this.token = res.data.data.token
})
}
},
getters:{
// 这里取名不可与state里的变量一致 所以取名getNum
//简写
getNum:state=>state.num,
//全写
// getNum:(state)=>{
// return state.num
// }
getToken:state=>state.token,
}
})
相应组件页面使用
home.vue
<template>
<div class="c">this is home page</div>
<div class="c">
<p>使用pinia直接改变变量</p>
<!-- 解构赋值后直接在template模板里调用变量和方法 -->
<p>{{ num }}</p>
<button @click="changeNum">点击递增</button>
</div>
<div class="c">
<button @click="changeToken">使用pinia请求数据接口赋值token</button>
<p>token: <span>{{ token }}</span></p>
</div>
</template>
<script lang="ts" setup>
import { toRefs } from 'vue'
// 1 引入
import { useHomeStore } from "../store/home";
// 2 拿到实例
const homeStore = useHomeStore();
// 3 解构里面的变量和方法 toRefs作用是让解构出来的变量具有响应性
const { num,changeNum,token,changeToken } = toRefs(homeStore);
</script>
<style scoped>
.c {
width: 80%;
padding: 20px;
margin: 0 auto;
border: 1px solid red;
}
.c>p>span{
color:coral;
}
</style>
效果:
pinia 也存在和vuex一样的弊端 就是刷新页面后 数据丢失
我们可以使用 pinia-plugin-persistedstate 插件来完成数据持久化
数据持久化具体步骤
1 下载插件 pinia-plugin-persistedstate
npm i pinia-plugin-persistedstate
2 main.ts引入和使用插件
main.ts
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import elementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// ① 引入createPinia方法从pinia
import { createPinia } from 'pinia'
// ② 拿到pinia实例
const pinia = createPinia()
// 1 引入数据持久化插件
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
// 2 pinia使用数据持久化插件
pinia.use(piniaPluginPersistedstate)
const app = createApp(App)
//使用pinia
app.use(router).use(elementPlus).use(pinia).mount('#app')
3 对应状态管理文件配置参数(这里以home.ts为例)
home.ts
// 每个状态管理文件都要引入此方法
import { defineStore } from 'pinia'
//引入接口
import { httpPost } from '../request/api'
// 官方建议取名遵从 useXXXStore 形式
// 'home' 为当前store的唯一标识 类似ID
// 取名建议与文件名称一致 便于记忆和管理
// pinia舍弃了冗长的mutations属性
// 以下是pinia的一种写法 因与vuex相似 便于学习和记忆
export const useHomeStore = defineStore('home',{
state:()=>{
return{
num:0,
token:''
}
},
//state也可写成这样
// state:()=>({
// num:0
// }),
actions:{
changeNum(){
//这里可以使用this去拿到state里定义的变量 下面同理
this.num ++
},
changeToken(){
// ts 实在学的不咋地 这里就先any了
httpPost().then((res:any)=>{
this.token = res.data.data.token
})
}
},
getters:{
// 这里取名不可与state里的变量一致 所以取名getNum
//简写
getNum:state=>state.num,
//全写
// getNum:(state)=>{
// return state.num
// }
getToken:state=>state.token,
},
//数据持久化配置 这里是当前所有变量都持久化
persist:true
})
效果:
在实际项目里 token持久化是我们所不希望的 那如何只让num这一变量持久化呢
进一步配置参数即可
home.ts
// 每个状态管理文件都要引入此方法
import { defineStore } from 'pinia'
//引入接口
import { httpPost } from '../request/api'
// 官方建议取名遵从 useXXXStore 形式
// 'home' 为当前store的唯一标识 类似ID
// 取名建议与文件名称一致 便于记忆和管理
// pinia舍弃了冗长的mutations属性
// 以下是pinia的一种写法 因与vuex相似 便于学习和记忆
export const useHomeStore = defineStore('home',{
state:()=>{
return{
num:0,
token:''
}
},
//state也可写成这样
// state:()=>({
// num:0
// }),
actions:{
changeNum(){
//这里可以使用this去拿到state里定义的变量 下面同理
this.num ++
},
changeToken(){
// ts 实在学的不咋地 这里就先any了
httpPost().then((res:any)=>{
this.token = res.data.data.token
})
}
},
getters:{
// 这里取名不可与state里的变量一致 所以取名getNum
//简写
getNum:state=>state.num,
//全写
// getNum:(state)=>{
// return state.num
// }
getToken:state=>state.token,
},
//数据持久化配置 这里是当前所有变量都持久化
// persist:true
//按需配置数据持久化 这里指定变量num保持持久化
persist:{
//默认名称为当前store唯一标识 这里即home
key:'homeNum',
//默认localStorage 本地储存
//这里建议临时储存sessionStorage 也可写成window.sessionStorage
storage:sessionStorage,
//默认当前store里的所有变量都持久化
paths:['num']
}
})
效果:
最后总结一下pinia一些优点
① 舍弃了冗长的 mutations 属性
② 舍弃了模块化 modules 让状态管理更加扁平化
③ 对于 ts 的支持更加友好 支持数据推断
④ 你甚至可以让各个状态管理相互依赖、嵌套
以上就是我目前在学习 pinia 的一些分享了 也欢迎看到这里的你一起分享学习 共同进步!