Pinia 使用详解
vue3-vite-less-配置别名-多环境_链接地址
vue3 路由和状态管理(pinia)传送门
pinia用法分为两种: options AIP, composition AIP 分别对应了vue的option 写法和 setup 写法(piniay option api 写法也支持在 vue setup中使用)
当不知道使用哪种方式的时候,官网建议我们首先使用 options Api
下面我们开始探讨两种方式的用法和区别(vue3)
Option API
安装pinia
执行 npm install pinia, 由于是新建的vue3项目,直接安装默认最新稳定版本就可以, 如果有同学需要学习用法,建议还是下载最新版本学习,不存在版本兼容问题
创建pinia
在 src 目录下,新建 store/index.ts。其中代码如下
import { createPinia } from "pinia";
// 创建pinia
export const store = createPinia();
在 src/main.ts 文件中引入
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// 导入pinia
import { pinia } from './store'
createApp(App)
.use(pinia)
.use(ElementPlus)
.mount('#app')
这样就将pinia 引入到项目中,pinia的用法和vueX的用法不太一样。导入的pinia并不是存放状态(state)、getter、actions的。下面开始正式进入option api的介绍。
使用option Api 创建store
接着在 src/sotre/index.ts中增加代码
import { createPinia, defineStore } from "pinia";
// 创建pinia
export const pinia = createPinia();
/**
* 创建一个store使用函数,
* defineStore 调用,并不会真正创建一个store,
* 只用在使用的时候(调用 userHandlerInfo())的时候,
* 才会真正创建store。
* 所在,在命名的时候 使用 use功能名称,
* 需要创建store时: const store = user功能名称();
*/
export const useHandlerInfo = defineStore("USER_INFO", {
// 通过箭头函数返回一个初始化的状态 option api 定义只有这种写法
state: () => {
return {
name: "王日天",
phone: "18888888",
}
},
// 定义获取状态的方法
getters: {
/**
* 传入state,通过state 获取状态
* 通过state获取的时候可以使用箭头函数
* @param state
* @returns
*/
getName: (state) => {
return state.name;
},
/**
* 什么都不传入,直接通过this 获取状态
* 通过this获取不能使用箭头函数,
* 其中的this就是 store实例
*/
getPhone(): string{
return this.phone;
}
},
// 修改state 的方法
actions: {
/**
* 通过外界传来的 name,赋值给store中的name
* 其中的this 也是 store 实例
* @param name
*/
setName(name: string){
this.name = name;
},
setPhone(p: string){
this.phone = p;
}
}
})
注释要比代码多,
defindStore接受两个参数,第一个参数为 id, 这个参数是必须要的,pinia通过这个id来连接开发工具。第二个参数,用来配置store。
defindStore 并不会直接创建 store, 只有在使用 use***()方法的时候,才会真正创建一个store
getters 和 actions中的this 就是创建成store之后的实例
到这里,一个使用option api 定义的store 就完成了。
读取,修改store中的数据
修改App.vue中的代码
导入src/store/index.ts 中定义的 userHandlerInfo。
使用mapState 读取数据,mapActions修改数据(和vueX差不多)
<script lang="ts">
//导入user***
import { useHandlerInfo } from "@/store"
import { mapActions, mapState } from "pinia";
export default {
data() {
return {}
},
computed: {
...mapState(useHandlerInfo, ['name', 'phone']),
...mapState(useHandlerInfo, {
// // 通过mapState 取别名获取
alias: 'name',
// 自定义函数获取
toFormat: (store) => {
const phone = store.getPhone;
return phone + "通过方法转换";
}
})
},
methods: {
...mapActions(useHandlerInfo, ['setName', 'setPhone']),
// 通过别名获取 actions中的方法
...mapActions(useHandlerInfo, {setAlias: 'setName'}),
},
mounted(){
setTimeout(() => {
this.setName("张三丰");
this.setPhone("732432488");
console.log(this.name);
}, 2000);
setTimeout(() => {
this.setAlias("武当掌门 张三丰");
}, 5000)
}
}
</script>
<template>
<div class="show-content">内容展示区域
<div>{{name}}</div>
<div>{{phone}}</div>
<div>{{alias}}</div>
<div>{{toFormat}}</div>
</div>
</template>
<style scoped lang="less">
.show-content {
color: #333;
font-size: 14px;
background: rgb(110, 166, 204);
}
</style>
查看页面结果
在setup() 函数中使用store
<script lang="ts">
//导入user***
import { useHandlerInfo } from "@/store"
import { mapActions, mapState } from "pinia";
import { onMounted } from "vue";
export default {
setup() {
const store = useHandlerInfo();
onMounted(() => {
setTimeout(() => {
// 修改数据
store.setName("张三丰");
store.setPhone("80909889")
}, 3000)
})
return {
store,
}
}
}
</script>
<template>
<div class="show-content">内容展示区域
// 读取数据
<div>{{store.getName}}</div>
<div>{{store.getPhone}}</div>
</div>
</template>
<style scoped lang="less">
.show-content {
color: #333;
font-size: 14px;
background: rgb(110, 166, 204);
}
</style>
通过在 script 中加 setup来使用 sotre(极简模式,vue3,推荐优选选择这种写法)
<script lang="ts" setup>
//导入user***
import { useHandlerInfo } from "@/store"
import { onMounted } from "vue";
const store = useHandlerInfo();
// 对应vue2 的mouted 生命周期
onMounted(() => {
setTimeout(() => {
store.setName("张三丰 飞升成仙");
store.setPhone("9874354")
}, 5000)
})
</script>
<template>
<div class="show-content">内容展示区域
// 读取数据
<div>{{store.getName}}</div>
<div>{{store.getPhone}}</div>
</div>
</template>
<style scoped lang="less">
.show-content {
color: #333;
font-size: 14px;
background: rgb(110, 166, 204);
}
</style>
可以看到setup 中也可以使用 option api创建的 store。并且使用方法要比option api 创建的vue简单。其中在script 标签上 加入 setup, 直接在script 书写逻辑,是最简单的。
这就是options Api 创建 store 的使用
Composition API 创建store
pinia 的安装和引入都是和 options api一样的
定义store
继续在scr/store/index.ts里面添加一个use***的声明
import { createPinia, defineStore } from "pinia";
import { computed, ref } from "vue";
// 创建pinia
export const pinia = createPinia();
/**
* 使用 composition API 定义store
* 第一个参数是 id, 第二个参数是一个函数
* 在这种语法中,第二个参数变成了一个函数,
* 函数里面 的 ref 变成了 options API 里面的state,
* 里面的 computed 变成了 options API 里面额 getter
* 里面的 function 变成了 options API 里面的 action
*
* 最后一步,一点过要把这些声明返回来
*/
export const useUserInfo = defineStore("USER_INFO_2", () => {
// 使用 ref 创建一个 状态
const age = ref(99);
const sex = ref("人妖");
// 使用 computed 创建一个 getter
const getAge = computed(() => age);
const getSex = computed(() => sex);
// 使用function 创建一个 action
function setAge(a: number) {
age.value = a;
}
function setSex(s: string){
sex.value = s;
}
return {age, sex, getAge, getSex, setAge, setSex};
})
可以看到 composition Api 的定义store 和 option api 定义完全不一样。composition Api 定义store的时候用到了vue 包里面的 ref, computed。其中
把官网中的描述,抄写到注释里面了。
读取,修改store中的数据
继续在App.vue文件中进行操作, 导入刚刚在src/store/index.ts 文件加中声明的 useUserInfo(使用 用户信息 use***)。
在javascript 标签中 加setup 使用,
<script lang="ts" setup>
//导入user***
import { useHandlerInfo, useUserInfo } from "@/store"
import { onMounted } from "vue";
// options api 定义的store
const store = useHandlerInfo();
// composition api 定义的store
const userStore = useUserInfo();
// 对应vue2 的mouted 生命周期
onMounted(() => {
setTimeout(() => {
// option api 定义的 store 修改数据
store.setName("张三丰 飞升成仙");
store.setPhone("9874354")
// composition api 定义的store 修改数据
userStore.setAge(88);
userStore.setSex("泰国人妖");
}, 5000)
})
</script>
<template>
<div class="show-content">内容展示区域
// 读取数据
<div>{{store.getName}}</div>
<div>{{store.getPhone}}</div>
composition api 定义的store 获取数据
<div>age: {{userStore.getAge}}</div>
<div>sex: {{userStore.getSex}}</div>
</div>
</template>
<style scoped lang="less">
.show-content {
color: #333;
font-size: 14px;
background: rgb(110, 166, 204);
}
</style>
可以看到使用的时候,和options api 声明的store在javascript 中添加setue使用差不多
使用 setup() 方法来使用
代码如下,
<script lang="ts">
//导入user***
import { useHandlerInfo, useUserInfo } from "@/store"
export default{
setup(){
// options api 定义的store
const store = useHandlerInfo();
// composition api 定义的store
const userStore = useUserInfo();
return {
store,
userStore,
}
},
mounted() {
setTimeout(() => {
// option api 定义的 store 修改数据
this.store.setName("张三丰 飞升成仙");
this.store.setPhone("9874354")
// composition api 定义的store 修改数据
this.userStore.setAge(88);
this.userStore.setSex("泰国人妖");
}, 5000)
}
}
</script>
<template>
<div class="show-content">内容展示区域
// 读取数据
<div>{{store.getName}}</div>
<div>{{store.getPhone}}</div>
composition api 定义的store 获取数据
<div>age: {{userStore.getAge}}</div>
<div>sex: {{userStore.getSex}}</div>
</div>
</template>
<style scoped lang="less">
.show-content {
color: #333;
font-size: 14px;
background: rgb(110, 166, 204);
}
</style>
可以看到使用的时候,和options api 声明的store在setue()函数中使用差不多。
compostion api 声明的store 能否在 option 方式定义的 Vue组件中使用,官网上没有看到明确的说明(也可能是我看漏了,大家可以去看看,记得回来告诉我)
storeToRefs
在setup中使用 store的时候,前面我们一直是返回的整个stroe,
有时候,我们需要使用单个属性,就需要用到 storeToRefs
使用方式如下
setup(){
// composition api 定义的store
const userStore = useUserInfo();
// 返回单个属性,并保持响应式
// 千万不要使用 es6 的解构赋值,es6 解构赋值之后,会取消响应式
const {getAge, getSex} = storeToRefs(userStore);
return {
userStore,
getAge,
getSex,
}
},
然后就可以在代码中使用 getAge, getSex,和声明在 setUp()中的属性一样使用
我们照例贴上官网权威说明, 其中最重要的两句,已经圈出来, only using state(没法使用 actions里面的方法);keeipng its reactivity (保持响应式, store中数据变化之后,使用数据的地方自动改变)
option api 定义的store 和 composition api定义的 store,都可以使用 storeTorefs();
需要注意的是只能在 setup() 方法中使用, 或者在javascript 标签上加了setup 的组件上使用
类型声明,类型声明需要熟悉ts
类型声明和ts类型声明一样,直接弄上官网连接和图
两种类型声明都比较简单。
pinia 的基本使用方法,也就介绍完成了。