8、Vue进阶三
Vuex状态管理
Vuex安装
state属性
模版引用
Options API中使用
Composition API中使用
getters属性
getters扩展一
getters扩展二
mutations属性
actions属性
组件中引用
参数传递
modules属性
模版中引用
其他属性
Pinia状态管理
Pinia相比Vuex
安装Pinia
Pinia基本使用
定义Store
state属性
模版中使用
对象解构
修改数据
批量修改
更新store
重置store
前期总结
getters属性
getters扩展一
getters扩展二
getters扩展三
actions属性
参数传递
Vuex安装
state属性
模版引用
Options API中使用
Composition API中使用
getters属性
getters扩展一
getters扩展二
mutations属性
actions属性
组件中引用
参数传递
modules属性
模版中引用
其他属性
Pinia状态管理
Pinia相比Vuex
安装Pinia
Pinia基本使用
定义Store
state属性
模版中使用
对象解构
修改数据
批量修改
更新store
重置store
前期总结
getters属性
getters扩展一
getters扩展二
getters扩展三
actions属性
参数传递
Vuex状态管理
Vuex是一个Vue官方专门为Vue.js应用程序开发的状态管理程序,它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化,组件之间的传值有父子组件通讯、祖先组件通讯,但是这种传参方式对于多层嵌套的组件就显得非常繁琐,代码维护起来非常麻烦;
因此Vue官方就提出了Vuex,Vuex就是把组件内需要进行共享的数据抽取出来,抽取到一个独立的仓库,进行统一管理,以一个全局的单例模式中管理,任何组件都可以使用,也可以对这个仓库内的状态进行增删改查,这就是Vuex,一个实现Vue下面全局共享状态的仓库;
Vuex安装
对于Vuex的安装也非常的简单,直接在项目目录下使用npm进行安装即可,目前的版本为4.1.0,如下示例;
[cce@doorta /usr/local/Project/front]# npm install vuex
state属性
如果希望将需要在组件间共享的数据放在Vuex中,首先建议将Vuex实现的状态共享功能,单独提取到一个模块中,这样更加利于以后的管理和维护;
那么同时,我们想要使用Vuex,首先必须在Vuex包中引入一个名为createStore的函数,利用该函数来创建一个仓库,createStore函数接收一个参数,该参数是一个对象,这个对象和Vue组件的Options API有点相似,它内部必须有一个state的函数,该函数返回一个对象,这个对象内就是需要进行全局共享的数据,和Options API的data函数很相似,如下示例;
// store.js
import {createStore} from "vuex"
const store = createStore({
state() {
return {
name: "cce"
}
}
})
export default store
那么因为我们将Vuex的逻辑全部提取到了一个模块中,所以我们应该将这个createStore函数创建的仓库暴露出去,然后在Vue项目中去导入这个仓库,并将其注册到Vue项目中,那么将Vuex仓库注册到Vue项目中,和路由是一样的,直接调用Vue实例的use方法即可,并Vuex仓库对象作为参数传递进去;
同样的,注册的Vuex仓库对象,必须在Vue实例mount之前进行注册,如下示例;
import {createApp} from 'vue'
import App from './App.vue'
import router from "./router.js"
import store from "./store.js"
const app = createApp(App)
app.use(router)
app.use(store) // 注册Vuex仓库
app.mount('#app')
模版引用
那么将Vuex仓库对象注册到Vue实例之后,就可以在全局使用这个共享仓库中的数据了,同样的,该数据也可以在模版中使用使用Mustache语法来引用,那么使用Mustache语法这个标识符就有点讲究了,需要使用{{ $store.state.var_name }}对象来获取Vuex对象中state函数返回的数据,和路由对象在模版中引用的方式是一样的,如下示例;
<template>
<div>
<h1>{{ $store.state.name }}</h1> <!-- 获取Vuex仓库对象中的name属性 -->
</div>
</template>
Options API中使用
如果我们希望在Vue 2的Options API中使用,可以直接使用this对象拿到这个$store对象,所以,在Options API中使用,直接使用this.$store.var_name去获取Vuex中的响应式数据即可,如下示例;
<template>
<div>
<h1>{{ name }}</h1>
</div>
</template>
<script>
export default {
data() {
return {
name: this.$store.state.name
}
}
}
</script>
Composition API中使用
如果我们希望在Vue 3的Composition API内的Setup函数中使用,和router是一样的,Vuex对象提供了一个useStore函数,该函数的返回值就是我们向Vue注册的那个仓库,所以在Vue 3的Setup函数中,就可以使用useStore函数的返回值直接拿到已注册的Vuex仓库对象,然后利用这个对象来访问共享仓库中的数据,如下示例;
<template>
<div>
<h1>{{ name }}</h1>
</div>
</template>
<script setup>
import {useStore} from "vuex"
const store = useStore()
let name = store.state.name // 拿到Vuex中的响应式数据
</script>
getters属性
在Vuex的对象中,还有一个getters属性,它类似computed计算属性,其主要作用,就是当数据需要先进行计算之后才能供组件使用时,就可以使用getters来实现,它也是一个对象,对象内有很多计算函数,每个计算函数都有两个参数,第一个参数为state,该参数是一个对象,可以直接通过这个state对象,来获取共享仓库中的响应式数据,第二个参数为getters,如下示例;
import {createStore} from "vuex"
const store = createStore({
state() {
return {
num: 10
}
},
getters: {
get_num(state) { // 定义计算方法
return state.num * 2
}
}
})
export default store
那么如果我们希望在模版中、Options API或者Composition API中拿到这个通过计算之后的结果时,就可以直接在已注册的store对象中的getters对象来获取这个getters函数;
但是,这里需要注意,我们并不需要显式调用这个计算函数,Vue会在渲染时,进行调用,所以,我们只需要提供对应getters函数标识符即可,如下示例;
<template>
<div>
<h1>{{ $store.getters.get_num }}</h1>
</div>
</template>
getters扩展一
其实getters属性内部的计算函数,还有第二个参数,即getters,如果在一个计算函数内需要用到另一个计算函数,那么就可以直接使用getters来获取其他的计算函数,但是需要注意的是,和上述一样,开发者无需显式调用这个函数,如下示例;
import {createStore} from "vuex"
const store = createStore({
state() {
return {
num: 10
}
},
getters: {
get_num(state) {
return state.num * 2
},
get_n(state, getters) {
return getters.get_num * 2 // 获取get_num计算函数
}
}
})
export default store
getters扩展二
如果希望给getters计算函数传递参数,实现根据参数的不同执行不同的操作,那么可以在getters对象内的计算函数直接返回一个函数,那么在模版中,或者Setup函数中等,调用的getters属性的时候,就需要可以显式的使用调用函数的语法来调用该计算函数返回的这个函数,从而一些动态的操作,如下示例;
// store.js
import {createStore} from "vuex"
const store = createStore({
state() {
return {
num: 10
}
},
getters: {
get_num(state) {
return function (n) { // 返回一个函数
return state.num * n
}
}
}
})
export default store
<template>
<div>
<h1>{{ $store.getters.get_num(2) }}</h1> <!-- 显式调用get_num返回的函数,并传入一个乘数 -->
<h1>{{ $store.getters.get_num(3) }}</h1>
</div>
</template>
mutations属性
如果想要修改Vuex共享仓库中的数据,虽然通过测试,可以直接使用拿到的state对象修改,但是Vue官方不推荐这样使用,如果需要修改Vuex中的数据,那么官方推荐的方式,就是通过Vuex的mutations属性来实现,因为Vuex是一个单例模式的程序,所以官方强制性要求,修改数据,只能通过mutations属性来实现,这也是Vuex的一个规范;
mutations属性是一个对象,该对象和getters类似,内部是一个一个的方法,这些方法就是用来定义如何去修改共享仓库中数据的一些函数,同时这些函数在回调时,默认会传递一个参数,即state对象,该对象,就是Vuex共享仓库的state对象,所以,如果需要修改仓库中的数据,直接使用这个对象获取到要修改的属性即可,如下示例;
import {createStore} from "vuex"
const store = createStore({
state() {
return {
name: "cce"
}
},
mutations: {
edit_name(state) { // 修改仓库中的name属性
state.name = 'cfj'
}
}
})
export default store
可以看到,这个mutations属性和我们Options API中的methods属性有点类似,methods属性是用来定义一些事件处理函数的,而mutations属性则是用来定义修改Vuex仓库中响应式数据的一些处理函数,那么处理函数当定义好了之后,在组件中,想要修改Vuex共享仓库的数据,就可以直接调用这个处理函数来实现;
那么调用这个处理函数也有点特殊,首先我们需要拿到已向Vue注册store对象,然后使用store对象的commit方法来调用对应的处理函数,具体调用哪一个处理函数,需要将处理函数的名称作为参数传到commit方法中,如下;
<template>
<div>
<h1>{{ $store.state.name }}</h1>
<button v-on:click="editName">修改</button>
</div>
</template>
<script setup>
import {useStore} from 'vuex'
const state = useStore()
let editName = function () {
state.commit("edit_name") // 调用edit_name函数
}
</script>
当然,我们如果希望给这个处理函数传递参数,只需要记住一个原则就行,第一个参数,必须是state对象,如果需要在处理函数中接收额外的参数,那么在除了state参数之外,再定义一个形参即可,那么在调用时,我们只需要在调用commit方法时,除了传入处理函数的名称之外,在传入一个实参即可;
actions属性
对于Vuex来讲,state属性,主要是用来存放响应式数据,而getters属性内部的处理函数主要是用来做计算的,计算state中的数据,然后返回给组件使用,mutations属性内部的处理函数主要是用来修改state中的数据的,那么如果我们希望通过网络获取数据,然后将数据存放到state中时,虽然这是一种修改数据的操作,但是并不推荐使用mutations来实现;
因为在开发过程中,作为开发者来讲常常会追踪状态的变化,常用的手段就是在浏览器控制台中调试,那么如果我们使用mutations来实现异步更新状态,虽然也会使状态正常更新,但是会导致开发者工具有时无法追踪到状态的变化,调试起来就会很困难,所以,如果我们通过mutations来实现异步更新状态,最大的问题就是,会造成响应式数据的状态在改变时,无法跟踪状态的变化;
那么如果想要执行一些异步操作,比如网络请求,官方推荐使用actions属性来实现,actions属性出现的目地,就是为了处理异步操作,但是需要注意的是,官方明确指明,如果需要修改state属性中的数据,必须使用mutations属性来实现,所以mutations是修改state数据的唯一途径;
因此,在这种场景下,当我们使用actions进行异步操作完成之后,如果希望将这个请求到的数据提交到Vuex仓库中,还是需要借助mutations来实现,即在actions里面显式调用mutations;
actions和mutations属性是一样的,它同样的是一个对象,这个对象内部有很多的异步处理函数,同时这些函数在回调时,默认会传入一个context参数,即上下文,context对象和store实例具有相同的方法和属性的,但是它并非store实例,所以如果希望在actions中调用mutations,可以直接调用context对象的commit来实现;
import {createStore} from "vuex"
const store = createStore({
state() {
return {
num: 10
}
},
mutations: {
edit_name(state, n) {
state.num *= n
}
},
actions: {
changgeNUM(context) { // 定义一个异步函数
setTimeout(function () { // 在2秒钟后触发一次mutations来修改仓库中的num数据
context.commit("edit_name", 3)
}, 2000)
}
}
})
export default store
组件中引用
那么如果我们希望在组件的Setup函数中触发这个actions异步函数的执行,和mutations的调用方法类似,首先,需要拿到store对象,然后调用这个store对象的dispatch方法,并传入对应的actions函数即可,如下示例;
<template>
<div>
<h1>{{ $store.state.num }}</h1>
<button v-on:click="changge">修改</button>
</div>
</template>
<script setup>
import {useStore} from "vuex"
const store = useStore() // 拿到store对象
function changge() {
store.dispatch('changgeNUM') // 触发名为changgeNUM的actions函数
}
</script>
参数传递
对于actions的参数传递和mutations一样,只要第一个参数,为对应actions属性中的函数名即可,后面的参数,将依次传递给actions属性对应的处理函数;
modules属性
当项目变得越来越大时,组件也会随之增多,那么当组件增多时,我们需要共享的数据也会随之变得越来越多,久而久之,Vuex的状态管理库会变得越来越庞大,以至于难以维护的地步,因此,Vuex提供了一个modules属性;
modules属性,可以将一个较大的共享仓库,进行模块划分,将一个较大的Vuex共享仓库以模块的形式进行拆分,每个模块下,都可以有自己的state、getters、mutations、actions属性,如下示例;
import {createStore} from "vuex"
const store = createStore({
modules: {
home: {
state() {
return {component_name: "home"}
}
},
user: {
state() {
return {component_name: "user"}
}
}
}
})
export default store
模版中引用
那么当我们将Vuex仓库对象进行模块划分之后,每个模块中的state响应式数据,在模版中引用的方式也有一些改变,原来引用的方式为{{ $store.state.var_name }},那么进行模块化划分之后,语法就变成了{{ $store.state.module_name.var_name }},如下示例;
<template>
<div>
<h1>{{ $store.state.home.component_name }}</h1>
</div>
</template>
其他属性
上述,我们只是演示了一个基础的state属性,在Vuex中还有getters、mutations及actions这三个属性,其实这三个属性的定义及使用和之前是一摸一样的,因为Vuex默认会将modules中的getters、mutations及actions合并到根模块(所谓根模块就是Vuex的根模块)当中的,所以对于使用上来讲没有任何区别,如下示例;
import {createStore} from "vuex"
const store = createStore({
modules: {
home: {
state() {
return {
num: 0
}
},
getters: {
get_num(state) {
return state.num + 1
}
},
mutations: {
edit_num(state, n) {
state.num += n
}
},
actions: {
edit_num_action(context) {
setTimeout(() => {
context.commit("edit_num", 10)
}, 2000)
}
}
}
}
})
export default store
<template>
<div>
<h1>{{ $store.getters.get_num }}</h1>
<button v-on:click="edit">修改</button>
</div>
</template>
<script setup>
import {useStore} from "vuex"
const store = useStore()
function edit() {
store.dispatch('edit_num_action', 10)
}
</script>
可以看到,Vuex默认会将子模块中的getters、mutations及actions这三个属性合并到根模块,所以我们在使用的时候,和没有使用模块时是一摸一样的,所以在开发时候,特别需要注意,这些属性中的处理方法,不要出现重名的可能,其实Vuex为了解决这个问题,也提出了一种解决方案,就是通过namespace来划分模块,这样每个模块都独立起来,这样就完全解决了重名的可能,但是由于其语法实在太过于丑陋,因此就不在此演示了,具体请查询官方文档;
Pinia状态管理
Pinia起源于2019年的一次探索Vuex下一个版本迭代的实验,所以,它结合了Vuex 5核心团队的许多想法,本来是准备开发Vuex 5版本的,但是由于Pinia已经实现了Vuex 5的大部分内容,所以最终决定使用Pinia来代替Vuex,所以从这一来看,其实Pinia就是Vuex 4.x的一个升级版,只不过换了个名称而已;
Pinia本质依然是一个状态管理的库,用于跨组件、页面进行状态共享,这点和Vuex是一样的,但与Vuex 相比,Pinia不仅提供了一个更简单的API,并且去除了Vuex中很多的限制,比如,修改数据必须使用mutations,异步处理必须使用actions等等;
同时Pinia还提供了更加符合Composition API风格的API,并且同时兼容Vue 2.x和Vue 3.x,在Vue 3.x中,更加推荐使用Pinia来进行状态管理;
Pinia相比Vuex
在Pinia中,已经去除了mutations属性,mutations使用确实受到不少开发者的诟病,因此在Pinia将其不再进行支持,同时,在Pinia中不再支持modules,没有模块的概念,可以通过多个store来实现这种特性,每个store相互独立,互不影响,同时,在Pinia中,也不再支持namespace的概念,不需要记住它们之间的复杂关系;
因此,在Pinia中,就仅支持三个属性,即state、getters和actions;
安装Pinia
对于Pinia的安装也非常的简单,直接在项目目录下使用npm进行安装即可,目前的版本为2.0.23,如下示例;
[cce@doorta /usr/local/Project/front]# npm install pinia
Pinia基本使用
Pinia的使用方式和Vuex大不相同,开发者无需在创建Pinia实例时,直接定义state、getters和actions属性,只需要将这个Pinia实例注册到Vue实例当中即可,如下实例;
// pinia.js
import {createPinia} from "pinia"
export default createPinia() // 创建一个Pinia实例,并暴露出去
// main.js
import {createApp} from 'vue'
import App from './App.vue'
import router from "./router.js"
import pinia from "./stores/pinia";
const app = createApp(App)
app.use(router)
app.use(pinia) // 注册pinia实例
app.mount('#app')
至此,我们的pinia已经正式注册到Vue项目中,那么我们想要定义响应式数据和方法,我们不需要直接在这个pinia实例中直接定义,我们可以单独给一个组件、或者一种类型,以模块的方式单独定义一个store仓库,且这样的仓库可以定义无数个,并且这些仓库我们也无需直接注册到pinia实例中,就可以直接在模版中、Options API及Composition API中使用;
定义Store
那么想要定义store仓库,我们就需要从pinia包中拿到一个defineStore的方法,该方法就是用来定义store仓库的,该方法接收两个参数;
第一个参数为该Store仓库的唯一标识符,即仓库ID,因为我们在开发中会定义很多的Store仓库,所以我们必须给每一个仓库定义一个唯一的标识符,第二个参数是一个对象,这个对象就是用来定义我们的state、getters及actions等属性的,如下示例;
// home.js
import {defineStore} from "pinia"
export default defineStore("home", {}) // 定义一个名为home的Store仓库
state属性
那么当我们的Store仓库定义好了之后,我们就可以在这个仓库内定义类似Vuex的state状态仓库了,Pinia中的state属性和Vuex的state属性是一样的,它也是一个函数,且这个函数需要返回一个对象,对象内就是需要共享的响应式数据,如下示例;
// home.js
import {defineStore} from "pinia"
const useHome = defineStore("home", {
state() { // 定义state状态仓库
return {
component_name: "home"
}
}
})
export default useHome
模版中使用
defineStore方法,默认会返回一个函数,该函数的返回值就是这个使用defineStore方法定义的Store仓库对象,同时,该函数一般情况下,我们会使用use开头来命名,这是一种规范;
那么当我们希望在模版中使用这个仓库中共享的响应式数据时,我们就需要拿到这个defineStore方法返回的函数,并调用该函数拿到对应的Store仓库对象;
那么如果希望利用这个store对象,在模版中拿到该store中共享的响应式数据时,就不再像Vuex中那样复杂了,直接使用对象的形式,在store对象内取出,state函数返回的共享的响应式数据即可,如下示例;
<template>
<div>
<h1>{{ homeStore.component_name }}</h1> <!-- 直接通过对象的方式,在store中拿到响应式数据 -->
</div>
</template>
<script setup>
import useHome from "../stores/home" // 导入defineStore方法的返回值
const homeStore = useHome() // 调用defineStore方法的返回值,拿到store对象
</script>
对象解构
可以看到,我们直接通过defineStore方法返回的函数的返回值就可以拿到store对象,在这个对象内就有我们共享的响应式数据,即state函数返回的数据,但是我们需要知道的是,虽然,我们可以使用对象的方式拿到state函数返回的数据,但是是不可以直接对它使用对象解构的方法去拿到的,因为这样,这种方式对共享数据的操作,不支持响应式;
修改数据
如果我们系统修改state函数返回的对象内的数据时,相比Vuex简单了太多太多,我们直接使用store对象对对应的属性进行赋值即可,如下示例;
<template>
<div>
<h1>{{ homeStore.component_name }}</h1>
<button v-on:click="changge">修改数据</button>
</div>
</template>
<script setup>
import useHome from "../stores/home"
const homeStore = useHome()
function changge() {
homeStore.component_name = "homeComponent" // 直接使用store对象来进行修改
}
</script>
批量修改
上述修改state的方式是一个一个的修改,如果我们希望一次性修改多个属性,Pinia其实也给我们提供了对应的方法,我们只需要调用store对象的$patch方法即可,$patch有一个参数,该参数是一个对象,对象内的属性和值,就是需要修改的属性和值,如下示例;
<template>
<div>
<h1>{{ homeStore.component_name }}</h1>
<button v-on:click="changge">修改仓库内数据</button>
</div>
</template>
<script setup>
import useHome from "../stores/home"
const homeStore = useHome()
function changge() { // 修改共享的响应式数据
homeStore.$patch({
component_name: "homeComponent"
})
}
</script>
更新store
如果我们希望更新store函数返回的对象,Pinia也提供了一种非常便捷的方法,即调用store对象的$state方法即可,该方法是一个函数,接收一个对象,该对象会直接覆盖原有state函数返回的共享响应式对象;
当我们将中属性赋值为一个对象时,会直接覆盖Store中共享的响应式数据,如下示例;
<template>
<div>
<h1>{{ homeStore.component_name }}</h1>
<button v-on:click="changge">修改仓库内数据</button>
</div>
</template>
<script setup>
import useHome from "../stores/home"
const homeStore = useHome()
function changge() { // 修改共享的响应式数据
homeStore.$state = {
component_name: "homeComponent",
component_url: "/home"
}
}
</script>
重置store
Pinia内部有个机制,它会记录store最初的状态,其主要用途就是用来重置Store,在store对象中,还提供了一个重置store的属性,即$reset,当我们调用这个方法时,默认会将store恢复成最初的形式,如下示例;
<template>
<div>
<h1>{{ homeStore.component_name }}</h1>
<button v-on:click="changge">修改仓库内数据</button>
<button v-on:click="resetStore">重置仓库</button>
</div>
</template>
<script setup>
import useHome from "../stores/home"
const homeStore = useHome()
function changge() { // 修改共享的响应式数据
homeStore.component_name = "homeComponent"
}
function resetStore() {
homeStore.$reset() // 重置当前Store仓库
}
</script>
前期总结
在对Pinia做了基本了解之后,会发现,它的定义和使用,非常的简单,相比Vuex来讲,复杂程度降低了N个等级,强大的模块化机制,让我们的代码编排方式更加的灵活;
其实一个Store就是一个实体,它有点像始终存在,并且任何地方都可以读取和写入的一个组件,我们可以在程序中,定义任意数量的Store来管理共享的响应式数据;
Store有三个核心的属性,即state、getters和actions,一旦store(defineStore方法返回的函数的返回值)被实例化,就可以直接使用这个实例化对象来访问state、getters和actions中定义的任何属性;
getters属性
Pinia中的getters属性和Vuex中的getters定义方法一摸一样,它们的基础的概念也是一摸一样的,就是如果我们想要对某些数据进行计算之后提供使时,就可以使用getters来实现;
同样的,getters也是一个对象,对象内有众多的计算函数,每个计算函数默认在回调时都会传递一个state的参数,我们可以通过这个state参数来获取到state中共享的响应式数据,此外,该函数的返回值就是计算后的结果,可以直接在模版、Options API和Composition API中使用,如下示例;
import {defineStore} from "pinia"
const useHome = defineStore("home", {
state() {
return {
num: 10
}
},
getters: {
chenggeNum(state) {
return state.num * 2
}
}
})
export default useHome
getters属性内部的计算函数,都会直接绑定在store对象上,如果想要将这个getters内部的函数在模版、Options API和Composition API中使用,直接使用store对象来调用即可,但是这里需要注意的是,这里并不需要显式调用这个函数,我们直接使用属性的方式访问即可,如下示例;
<template>
<div>
<h1>{{ homeStore.chenggeNum }}</h1>
</div>
</template>
<script setup>
import useHome from "../stores/home"
const homeStore = useHome()
console.log("getters计算方法结果为:", homeStore.chenggeNum)
</script>
getters扩展一
如果我们希望,在一个getters函数内调用另一个getters函数时,我们可以直接使用this对象拿到对应的getters函数函数,当然,在使用时,我们也无需显式调用这个getters函数,只需要以属性的方式访问即可,详情查看上述的Vuex扩展一;
getters扩展二
对于Pinia当中的getters属性内部的函数,也Vuex当中的getters属性内部的函数是一样的,它也支持返回一个函数,如果我们希望给getters属性内部的函数传参,那么直接将这个getters属性内部的函数返回一个带参的函数即可,详情查看上述的Vuex扩展二;
getters扩展三
如果getters属性内部的函数需要用到别的store当中的数据或者方法时,一样的,我们只需要导入defineStore方法返回的函数对象,然后拿到这个函数的返回值去访问即可,具体的不做过多的赘述,很简单;
actions属性
对于Pinia来讲,它actions属性和Vuex当中的actions属性的定义方式是一样的,都是一个对象,对象内有众多的异步方法函数,唯一和Vuex不同的是,Pinia当中的actions函数,在回调时,不会传递任何参数;
此外,Pinia当中的actions内部的方法函数都可以直接通过this对象来访问到getters和state对象内的法和属性,但是这里需要注意的是,this是会有绑定问题的,所以在这种场景下,如果我们编写一个传统的action函数,那么this就会绑定到Window对象,所以在actions属性内的异步方法,我们建议直接使用箭头函数,如下示例;
import {defineStore} from "pinia"
const useHome = defineStore("home", {
state() {
return {
num: 10
}
},
actions: {
chenggeNum() {
setTimeout(() => {
this.num *= 2
}, 2000)
}
}
})
export default useHome
那么如果,我们希望在模版中、Options API和Composition API中调用actions属性内部的方法函数,其实它和Pinia的getters是一样的,直接使用store对象来调用即可,只不过对于actions来讲,我们不再像getters那样,使用属性的方式来调用,而是使用方法的方式来调用,如下示例;
<template>
<div>
<h1>{{ homeStore.num }}</h1>
<button v-on:click="homeStore.chenggeNum()">异步处理</button> <!-- 使用store对象来,调用actions函数 -->
</div>
</template>
<script setup>
import useHome from "../stores/home"
const homeStore = useHome()
</script>
参数传递
因为Pinia当中的actions属性内部的函数,和Vuex当中的actions属性内部的函数是不一样的,Vuex当中的actions属性内部的函数在回调时默认会传递一个context参数,而Pinia当中的actions属性内部的函数则不一样,它在回调时,不会传递任何参数;
所以,如果我们希望在Pinia当中的actions属性内部的函数定义参数,直接定义形参即可,然后在调用时,显式的传递一个实参;