Pinia
是VUE3的一个状态管理工具,官方文档说Pinia
是一个符合直觉的Vue.js状态管理库,相比于VUEX
,Pinia
没有那么复杂的流程,非常的简单而又直接。
VUEX和Pinia
VUE2的VUEX
和VUE3Pinia
都叫做集中式状态管理,这个状态说白了就是数据,就是用于管理存储数据的,包括REACT的Redux
。集中式的意思就是把所有要管理的数据都放在一个容器里统一管理,相对的就是分布式,比如分布式系统。
什么时候会用到这个集中式状态管理呢,就是当组件很多且来回嵌套层级很大的时候,此时单纯的父子组件传值已经不方便了,因为可能要传很多次,或者说组件之间根本就没有嵌套关系,父子组件无法传值,此时就可以用到集中式状态管理。如果只是某个组件自己要用或者说自己这个组件和上下嵌套的组件会用到的时候,就不要用集中式状态管理,直接把数据存储在该组件内或者用父子组件传值就好了。
Pinia的使用如何存储和读取数据
事前准备
我们先搭建一个场景,页面上有两块内容,一块是一个加减功能,另一块是获取动漫名称的内容。
CountView.vue
<template>
<div class="part-count-view">
<div class="sum">当前求和为:{{ sum }}</div>
<div class="btn">
<el-select v-model="num" style="width: 120px">
<el-option label="1" :value="1"></el-option>
<el-option label="2" :value="2"></el-option>
<el-option label="3" :value="3"></el-option>
<el-option label="4" :value="4"></el-option>
</el-select>
<el-button type="primary" @click="addFun" style="margin-left: 10px">加</el-button>
<el-button type="primary" @click="subFun">减</el-button>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
let sum = ref(1);
let num = ref(1);
function addFun() {
sum.value += num.value;
}
function subFun() {
sum.value -= num.value;
}
</script>
<style lang="scss" scoped>
.part-count-view {
box-sizing: border-box;
height: 100%;
padding: 10px;
.sum {
margin-top: 40px;
margin-bottom: 50px;
}
}
</style>
GetAnimeView.vue
<template>
<div class="part-anime-view">
<div class="btn">
<el-button @click="addAnime">添加一部动漫</el-button>
<el-button @click="subAnime">减少一部动漫</el-button>
</div>
<div class="container">
<ul>
<li v-for="(item, index) in animeList" :key="index">{{ item }}</li>
</ul>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { ElMessage } from "element-plus";
let allAnimes = ref(["海贼王", "火影忍者", "死神", "家庭教师", "全职猎人", "JOJO"]);
let index = ref(1);
let animeList = ref<string[]>(["海贼王"]);
function addAnime() {
if (index.value >= 6)
return ElMessage({
message: "已经没有动漫了!",
type: "warning",
});
index.value++;
animeList.value = allAnimes.value.slice(0, index.value);
}
function subAnime() {
if (index.value <= 1)
return ElMessage({
message: "最少保留一部动漫!",
type: "warning",
});
index.value--;
animeList.value = allAnimes.value.slice(0, index.value);
}
</script>
<style lang="scss" scoped>
.part-anime-view {
height: 100%;
.btn {
margin-top: 20px;
}
.container {
margin-top: 10px;
display: flex;
justify-content: center;
ul {
width: 50%;
}
}
}
</style>
index.vue
<template>
<div class="screen-view">
<div class="top">
<CountView></CountView>
</div>
<div class="bottom">
<GetAnimeView></GetAnimeView>
</div>
</div>
</template>
<script lang="ts" setup>
import CountView from "./components/CountView.vue";
import GetAnimeView from "./components/GetAnimeView.vue";
</script>
<style scoped lang="scss">
.screen-view {
height: 100%;
padding: 10px;
box-sizing: border-box;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
.top {
width: 500px;
height: 200px;
border-radius: 10px;
background-color: pink;
margin-bottom: 30px;
}
.bottom {
width: 500px;
height: 200px;
border-radius: 10px;
background-color: skyblue;
}
}
</style>
页面展示
搭建pinia环境
想使用pinia
需要先安装,如果在创建项目之前就配置好了就不用再安装了。
npm i pinia
安装完pinia
以后就要去搭建pinia
环境,首先去main.ts
文件中引入创建pinia
的函数,然后创建pinia
,最后再把pinia
应用到app
上。
main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
// 第一步:引入创建pinia的函数
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
// 第二步:创建pinia 最好再创建完app以后
const pinia = createPinia()
// 第三步:将pinia应用到app上
app.use(pinia)
app.use(router)
app.use(ElementPlus)
app.mount('#app')
这样以后pinia
的环境就搭建好了。
使用pinia存储+读取数据
pinia
强调一个东西叫做分类(这个分类跟前面说的把数据都放在一起统一管理不冲突),首先考虑项目中有多少个组件,然后考虑要把哪些数据存储进去。根据我们上面准备好的前提,一共有两个组件CountView
和GetAnimeView
两个组件,CountView
组件有一个求和数据sum
,GetAnimeView
组件有一个展示动漫的数据animeList
,这两个数据最后会存储在pinia
中。
首先在src
文件夹下创建一个文件夹叫做store
,熟悉VUE2的都知道这是配置VUEX
的文件夹,在VUE3里这里就是配置pinia
的。然后我们因为有两个组件CountView
和GetAnimeView
,所以这里面就要分类了,分成两个ts
文件去分别存储对应组件的数据,为了起名规范这两个ts
文件就叫做count.ts
和anime.ts
。
然后在文件里我们要从pinia
引入一个函数叫做defineStore
(虽然前面讲带define的函数可以省略引入,但是这个不能),然后执行这个函数赋值给一个变量,这就相当于创建一个store
专门存储CountView
组件的数据,变量名最好用Hooks
的形式,这里就叫做useCountStore
。
store/count.ts
import { defineStore } from 'pinia'
const useCountStore = defineStore()
然后就是要往defineStore
函数里面传参,有两个参数,第一个就相当于是这个store
的id
值,就是代表这个sotre
的名称,最好和文件名相同,所以这里就传count
,第二个参数是一个配置对象,其中有一个属性叫做state
,表示状态,其实也就是数据,这个是存储数据的地方(跟VUEX一样),如果是VUE2或者REACT,这里就是一个对象,但是VUE3里这是一个函数,然后return
出去一个对象,存储的数据就放在这里面,这里存储一下CountView
组件的求和数据sum
,然后给一个默认值7
。
store/count.ts
import { defineStore } from 'pinia'
const useCountStore = defineStore('count', {
state() {
return {
sum: 7
}
}
})
创建好store
以后我们肯定要用到它,所以这里还要给它暴露出去。
store/count.ts
import { defineStore } from 'pinia'
export const useCountStore = defineStore('count', {
state() {
return {
sum: 7
}
}
})
暴露出去以后呢我们就要在组件里面引入了,引入这个useCountStore
以后我们执行它,就可以获取到这个store
,然后把它赋值给一个变量,我们就可以通过操作这个变量去操作这个store
了,打印一下看看。
CountView.vue
<template>
<div class="part-count-view">
<div class="sum">当前求和为:{{ sum }}</div>
<div class="btn">
<el-select v-model="num" style="width: 120px">
<el-option label="1" :value="1"></el-option>
<el-option label="2" :value="2"></el-option>
<el-option label="3" :value="3"></el-option>
<el-option label="4" :value="4"></el-option>
</el-select>
<el-button type="primary" @click="addFun" style="margin-left: 10px">加</el-button>
<el-button type="primary" @click="subFun">减</el-button>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
// 引入创建的store
import { useCountStore } from "@/store/count";
// 执行这个store
const countStore = useCountStore()
console.log(countStore);
let sum = ref(1);
let num = ref(1);
function addFun() {
sum.value += num.value;
}
function subFun() {
sum.value -= num.value;
}
</script>
<style lang="scss" scoped>
.part-count-view {
box-sizing: border-box;
height: 100%;
padding: 10px;
.sum {
margin-top: 40px;
margin-bottom: 50px;
}
}
</style>
可以看到打印的是一个Proxy
对象,这就说明store
的数据是响应式的,里面就有一个属性sum
,就是我们放在state
里的数据,所以我们就可以直接通过countStore.sum
去获取这个数据。下面还有一个属性叫做$store
,这是一个对象,里面存储的数据也是我们存放在state
里的数据,所以我们也可以通过countStore.$state.sum
去获取,推荐第一种,简单。所以组件里面就不要自己定义sum
了,直接获取store
里的使用就可以了(实际项目种最好是中间在用一个变量过渡一下,不要直接修改state
里的数据,下面会讲)。
CountView.vue
<template>
<div class="part-count-view">
<!-- <div class="sum">当前求和为:{{ sum }}</div> -->
<div class="sum">当前求和为:{{ countStore.sum }}</div>
<div class="btn">
<el-select v-model="num" style="width: 120px">
<el-option label="1" :value="1"></el-option>
<el-option label="2" :value="2"></el-option>
<el-option label="3" :value="3"></el-option>
<el-option label="4" :value="4"></el-option>
</el-select>
<el-button type="primary" @click="addFun" style="margin-left: 10px">加</el-button>
<el-button type="primary" @click="subFun">减</el-button>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { useCountStore } from "@/store/count";
const countStore = useCountStore();
// let sum = ref(1)
let num = ref(1);
function addFun() {
countStore.sum += num.value;
// sum.value += num.value
}
function subFun() {
countStore.sum -= num.value;
// sum.value -= num.value
}
</script>
<style lang="scss" scoped>
.part-count-view {
box-sizing: border-box;
height: 100%;
padding: 10px;
.sum {
margin-top: 40px;
margin-bottom: 50px;
}
}
</style>
CountView
组件写完了,那么GetAnimeView
组件自然也是一样的道理。
store/anime.ts
import { defineStore } from 'pinia'
export const useAnimeStore = defineStore('anime', {
state() {
return {
animeList: ['海贼王']
}
}
})
GetAnimeView
<template>
<div class="part-anime-view">
<div class="btn">
<el-button @click="addAnime">添加一部动漫</el-button>
<el-button @click="subAnime">减少一部动漫</el-button>
</div>
<div class="container">
<ul>
<li v-for="(item, index) in animeStore.animeList" :key="index">{{ item }}</li>
<!-- <li v-for="(item, index) in animeList" :key="index">{{ item }}</li> -->
</ul>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { useAnimeStore } from "@/store/anime";
import { ElMessage } from "element-plus";
let allAnimes = ref(["海贼王", "火影忍者", "死神", "家庭教师", "全职猎人", "JOJO"]);
let index = ref(1);
// let animeList = ref<string[]>(['海贼王'])
const animeStore = useAnimeStore();
function addAnime() {
if (index.value >= 6)
return ElMessage({
message: "已经没有动漫了!",
type: "warning",
});
index.value++;
animeStore.animeList = allAnimes.value.slice(0, index.value);
// animeList.value = allAnimes.value.slice(0, index.value);
}
function subAnime() {
if (index.value <= 1)
return ElMessage({
message: "最少保留一部动漫!",
type: "warning",
});
index.value--;
animeStore.animeList = allAnimes.value.slice(0, index.value);
// animeList.value = allAnimes.value.slice(0, index.value);
}
</script>
<style lang="scss" scoped>
.part-anime-view {
height: 100%;
.btn {
margin-top: 20px;
}
.container {
margin-top: 10px;
display: flex;
justify-content: center;
ul {
width: 50%;
}
}
}
</style>
Pinia如何修改数据
讲完了pinia
的搭建配置,也讲了pinia
如何去存储读取数据,现在该讲如何去修改数据了,pinia
修改数据的方式一共有三种。
第一种修改方式 直接修改源数据
我们前面演示的时候也做了修改,就是直接去修改获取到的数据。
CountView.vue
import { ref } from "vue";
import { useCountStore } from "@/store/count";
const countStore = useCountStore();
// let sum = ref(1)
let num = ref(1);
function addFun() {
// 直接修改 store 里的源数据
countStore.sum += num.value;
// sum.value += num.value
}
function subFun() {
// 直接修改 store 里的源数据
countStore.sum -= num.value;
// sum.value -= num.value
}
这种方式也就只有在pinia
里是可用的了,在VUEX
会报错,所以这也是pinia
为什么被称为符合直觉(拿到数据就可以直接改)的状态管理库,但是一般不建议使用这种直接修改源数据的方式。
第二种修改方式 $patch
如果我们存储的数据很多的时候,继续用第一种修改方式就比较麻烦,我们先多添加几个数据试试:
store/count.ts
import { defineStore } from 'pinia'
export const useCountStore = defineStore('count', {
state() {
return {
sum: 7,
// 多添加的数据
name: 'Moon',
age: 18
}
}
})
然后在组件引入,添加一个按钮,点击按钮以后让sum+1
,name
和age
都修改。
CountView.vue
// 新增修改按钮
function change() {
countStore.sum += 1;
countStore.name = "月亮";
countStore.age = 19;
}
但是这样观感不够好,看起来很繁琐,如果数据再多一点,就要输入很多countStore.
,所以我们可以使用$patch
方法去批量修改。
如果细心的话会在前面打印的时候发现countStore
里面$patch
属性,这是一个方法,可以传入一个对象参数,把要修改的数据作为属性,修改的值作为属性值,去进行一个批量修改。
CountView.vue
// 新增修改按钮
function change() {
countStore.$patch({
sum: 8,
name: "月亮",
age: 18,
});
}
但是如果参数里有不属于原本的数据,就会报错,比如原本store
里state
的数据只有sum
,name
,age
,我们传一个address
进去,代码就会报错。
第三种修改方式 actions
actions
在VUEX
里就是用于修改数据的,里面会有修改数据的方法,VUE2和VUE3有很多地方都相似,所以这里actions
也是用于修改数据的。
在使用actions
之前我们要先去定义一下这个属性,actions
是一个对象,可以存储很多个属性,每个属性都是一个方法,用于去响应store
的一些操作,就比如修改数据的操作,我们举个例子,声明一个addFn
方法用于代替原本组件的加按钮
的方法。
store/count.ts
import { defineStore } from 'pinia'
export const useCountStore = defineStore('count', {
state() {
return {
sum: 7,
}
},
// 放置的是一个一个的方法,用于响应store的一些操作
actions: {
addFn() {}
}
})
但是我们要知道,我们计算加法的时候要根据选择不同的值去加,所以我们还要传参过去,所以这里还要有一个参数去接收传过来的值,如果要传多个,就多设置几个参数。
store/count.ts
import { defineStore } from 'pinia'
export const useCountStore = defineStore('count', {
state() {
return {
sum: 7,
}
},
// 放置的是一个一个的方法,用于响应store的一些操作
actions: {
addFn(value) {
console.log(value);
}
}
})
CountView.vue
// 加按钮
function addFun() {
// countStore.sum += num.value;
// sum.value += num.value
countStore.addFn(num.value);
}
这个时候就能获取到我们选择的值,那光有选择的值也不行啊,还得有原本的sum
值啊,这个该怎么取呢,难不成直接从state
里取吗?但是state
和actions
是不同的模块,是不能互相取值的,所以这个时候我们用到了this
,哎好久不见的this
,在这里打印一下this
看看是啥。
store/count.ts
import { defineStore } from 'pinia'
export const useCountStore = defineStore('count', {
state() {
return {
sum: 7,
}
},
// 放置的是一个一个的方法,用于响应store的一些操作
actions: {
addFn(value) {
console.log(value);
}
}
})
哎,可以看到这个this
就是store
,所以我们可以直接通过this.sum
去获取到sum
的值,所以最终代码就是:
store/count.ts
import { defineStore } from 'pinia'
export const useCountStore = defineStore('count', {
state() {
return {
sum: 7,
}
},
// 放置的是一个一个的方法,用于响应store的一些操作
actions: {
addFn(value) {
this.sum += value
}
}
})
此时actions
的功能就基本实现了,但是这不还是拿过来源数据进行直接修改吗?有什么意义呢,其实意义在于,actions
里面可以写一些逻辑,比如说限制sum
最大只能为10
。
store/count.ts
import { defineStore } from 'pinia'
export const useCountStore = defineStore('count', {
state() {
return {
sum: 7,
}
},
// 放置的是一个一个的方法,用于响应store的一些操作
actions: {
addFn(value) {
if (this.sum < 10) {
this.sum += value
}
}
}
})
但是这个逻辑我们在组件里面也可以写啊。
CountView.vue
// 加按钮
function addFun() {
// countStore.sum += num.value;
// sum.value += num.value
if (countStore.sum < 10) {
countStore.sum += num.value;
}
}
但是当这个方法用的比较多的时候,就可以减少代码量,实现代码复用,而且实际项目中不会这么去写,而是用一个中间变量去过渡,比如这样:
CountView.vue
import { ref } from "vue";
import { useCountStore } from "@/store/count";
const countStore = useCountStore();
let num = ref(1);
// 用一个中间变量来过渡,先把源数据值赋值给变量
let sum = countStore.sum
// 加按钮
function addFun() {
sum += num.value
// 修改以后再把变量的值设置为源数据的值
countStore.setSum(sum)
}
store/count.ts
import { defineStore } from 'pinia'
export const useCountStore = defineStore('count', {
state() {
return {
sum: 7,
}
},
// 放置的是一个一个的方法,用于响应store的一些操作
actions: {
// 把中间变量的值赋值给源数据
setSum(value) {
this.sum = value
}
}
})
storeToRefs
我们前面讲读取数据的时候都是怎么读取的,通过countStores.sum
或者countStroe.$state.sum
进行读取,但是这样是不是觉得很不方便,前面还得进行countStore.
,所以我们可以换一种方式进行读取数据。
那有人就会想到,我们能不能给它解构赋值出来呢?我们去试一下:
CountView.vue
<template>
<div class="part-count-view">
<!-- 将解构赋值出来的数据放在页面上 -->
<div class="sum">当前求和为:{{ sum }}</div>
<div class="btn">
<el-select v-model="num" style="width: 120px">
<el-option label="1" :value="1"></el-option>
<el-option label="2" :value="2"></el-option>
<el-option label="3" :value="3"></el-option>
<el-option label="4" :value="4"></el-option>
</el-select>
<el-button type="primary" @click="addFun" style="margin-left: 10px">加</el-button>
<el-button type="primary" @click="subFun">减</el-button>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { useCountStore } from "@/store/count";
const countStore = useCountStore();
let num = ref(1);
// 通过解构赋值的形式获取sum
let { sum } = countStore;
// 加按钮
function addFun() {
// 使用actions的方式操作sum
countStore.addFn(num.value);
console.log(countStore.sum); // 打印store上的sum
}
function subFun() {
countStore.sum -= num.value;
}
</script>
store/count.ts
import { defineStore } from 'pinia'
export const useCountStore = defineStore('count', {
state() {
return {
sum: 7,
}
},
actions: {
// 操作sum的方法
addFn(value) {
this.sum += value
}
}
})
会发现页面数据不变,但是实际上数据已经发生改变了,这一点像不像讲声明响应式数据的时候,从响应式数据上解构赋值出来的数据失去响应式,最后用toRefs
去解决这个问题,那么我们是否也可以用toRefs
去解决呢?我们试一下。
CountView.vue
// 解构赋值的时候用toRefs包裹
let { sum } = toRefs(countStore);
console.log(toRefs(countStore)); // 打印一下
此时解构出来的sum
确实变成响应式的了,也能正常使用,那我们是否就是说可以用这个方法呢?虽然使用toRefs
可以解决问题,但是最好不用,我们打印这个被toRefs
包裹起来的数据看看是个什么东西。
会发现它把里面所有的属性都变成响应式的了,其实我们只要sum
变成响应式的就好了,而且那addFn
是一个方法,你给变成响应式的干嘛。那有人又会说了,那我们用toRef
不就可以了吗,那我们问,如果我们解构的数据很多难不成一个一个去解构吗,所以这里有一个专门用于store
数据的方法storeToRefs
,当然要先从pinia
里面引入。
CountView.vue
import { storeToRefs } from "pinia";
// 解构赋值的时候用storeToRefs包裹
let { sum } = storeToRefs(countStore);
console.log(storeToRefs(countStore)); // 打印一下
可以发现解构出来的数据是响应式的了,能够实现功能,那我们再看看被storeToRefs
包裹起来的数据是什么样的。
可以看到里面没有什么杂七杂八的东西,只有存储的数据,没有方法之类的东西,所以这种方法更适合去解构store
里面的数据。
getters
VUEX
里面也有getters
,pinia
里面也有,那这个getters
是干嘛的呢?
其实就相当于是一个计算属性computed
,使用方式也是一样的,getters
是一个对象,里面的每一个属性都是一个计算属性,通过return
去返回一个被二次计算后的值。而且里面可以接受一个参数,这个参数就是state
,所以在getters
里面是可以获取到state
里面的值的,从而进行二次计算。当然这里面也可以用this
,不过VUE3已经减少this
的使用,所以建议直接用state
。
store/count.ts
import { defineStore } from 'pinia'
export const useCountStore = defineStore('count', {
state() {
return {
sum: 7,
}
},
actions: {
// 操作sum的方法
addFn(value) {
this.sum += value
}
},
// 类似于计算属性
getters: {
// 声明一个 sum * 10 的计算属性
bigSum(state) {
return state.sum * 10
}
}
})
而且getters
里面的数据是可以被stroeToRefs
去解构出来为响应式变量的。
// 解构赋值的时候用storeToRefs包裹
let { sum, bigSum } = storeToRefs(countStore);
console.log(storeToRefs(countStore)); // 打印一下
因为减少this
的使用,所以我们可以在getters
里面使用箭头函数更方便。
store/count.ts
getters: {
bigSum: state => state.sum * 10
}
$subscrie
我们前面讲了store
的一个方法$patch
,是用于批量修改数据的,这次讲一下$subscribe
方法,这个方法很简单,类似于监视器watch
,我们往这个方法里面传入一个回调函数,当store
里的数据发生变化的时候,这个回调函数就会去调用,回调函数接收两个参数mutate
和state
,mutate
是触发事件的一些相关信息,state
就是数据改变以后的store
里的state
。
CountView.vue
// $subscribe方法
countStore.$subscribe((mutate, state) => {
console.log("数据发生了变化");
console.log("mutate", mutate);
console.log("state", state);
});
store/count.ts
import { defineStore } from 'pinia'
export const useCountStore = defineStore('count', {
state() {
return {
sum: 7,
}
},
actions: {
// 操作sum的方法
addFn(value) {
this.sum += value
}
},
getters: {
bigSum: state => state.sum * 10
}
})
通过打印可以看出来state
就是修改以后的store
,这个一眼就看的明白,我们着重看一下mutate
,mutate
里面有一个属性叫做storeId
,就是我们前面讲的配置store
的时候设置的名字,这里是告诉你哪个store
的数据被修改了,还有一个属性叫做effect
,是一个对象,里面有一个属性key
,这个就是告诉我们修改的是哪个数据,而newValue
和oldValue
就好理解了,就是说数据修改之后的值和修改之前的值。
那如果同时修改多个数据会怎样呢?我们试一下,先给state
新增一个数据a
,值就为1,然后我们在修改sum
的时候把这个a
也修改一下。
CountView.vue
// $subscribe方法
countStore.$subscribe((mutate, state) => {
console.log("数据发生了变化");
console.log("mutate", mutate);
console.log("state", state);
});
// 加按钮
function addFun() {
countStore.addFn(num.value);
countStore.a++;
}
store/count.ts
import { defineStore } from 'pinia'
export const useCountStore = defineStore('count', {
state() {
return {
sum: 7,
a: 1 // 新增一个数据a
}
},
actions: {
addFn(value) {
this.sum += value
}
},
getters: {
bigSum: state => state.sum * 10
}
})
可以看到如果同时修改多个数据,$subscribe
方法只会触发一次,并且key
指的是最后修改的数据。
store的组合式写法
我们做了半天,有没有发现这个store
是选项式写法,里面的state
,actions
,getters
都是一个一个的选项,而VUE3不是组合式开发吗,所以我们给它改成组合式的写法。
store/count.ts 选项式写法
import { defineStore } from 'pinia'
export const useCountStore = defineStore('count', {
state() {
return {
sum: 7,
}
},
actions: {
addFn(value) {
this.sum += value
}
},
getters: {
bigSum: state => state.sum * 10
}
})
组合式写法的时候defineStore
的第二个参数就不是一个对象了,而是一个函数,然后在里面通过ref
去声明一个变量作为state
或者用computed
去声明一个计算属性也就是getters
,actions
方法就直接通过function
去定义一个方法,最后return
出去。
store/count.ts 组合式写法
import { ref } from 'vue'
import { computed } from 'vue'
export const useCountStore = defineStore('count', () => {
// 声明state的数据
let sum = ref(7)
// 声明action的方法
function addFn(value) {
sum.value += value
}
// 声明getters的计算属性
let bigSum = computed(() => {
return sum.value * 10
});
// 最后return出去,不return出去就获取不到里面的数据和方法
return { sum, addFn, bigSum }
})
这么看来,是不是很像刚开始讲的setup
,其实也差不多。