第四十四章 Vue之actions/mapActions/getters
目录
一、actions
1.1. 使用方法
1.2. 完整代码
1.2.1. index.js
1.2.2. main.js
1.2.3. App.vue
1.2.4. Son1.vue
1.2.5. Son2.vue
二、mapActions
2.1. 使用方法
2.2. 完整代码
三、getters
3.1. 使用方法
3.2. 完整代码
3.2.1. main.js
3.2.2. index.js
3.2.3. App.vue
3.2.4. Son1.vue
3.2.5. Son2.vue
一、actions
1.1. 使用方法
之前几个章节我们学习了通过mutations同步修改Vuex仓库数据,mutations 必须是同步的 (便于监测数据变化,记录调试),本章节我们将学习通过学习actions的基本语法,来处理对Vuex仓库的异步操作。
1. 提供action 方法
注意:actions处理异步,它不能直接操作state,操作state还是需要commit mutation
2. 页面中 dispatch 调用
1.2. 完整代码
1.2.1. index.js
// 存放的是vuex相关的核心代码
import Vue from 'vue'
import Vuex from 'vuex'
// 配置插件给Vue使用
Vue.use(Vuex)
// 创建仓库(空仓库)
const store = new Vuex.Store({
// 严格模式(有利于初学者,检测不规范的代码 => 上线的时候可以去掉)
strict: true,
// 1. 通过 state提供数据(所有组件可以共享)
state: {
title: '大标题',
count: 100
},
// 2. 通过 mutations 可以提供修改数据的方法
mutations: {
// 所有mutation函数,第一个参数,都是 state
addCount (state, n) {
// 修改数据
state.count += n
},
subCount (state, n) {
// 修改数据
state.count -= n
},
changeTitle (state, obj) {
state.title = obj.newTitle
},
changeCount (state, newCount) {
state.count += newCount
}
},
// 3. actions处理异步,它不能直接操作state,操作state还是需要commit mutation
actions: {
// context 上下文 (此处因为我们还未分模块,可以当成store仓库)
// context.commit('mutation名字', 额外参数)
changeCountAction (context, num) {
// 这里是setTimeout模拟异步,以后大部分场景是发请求
setTimeout(() => {
context.commit('changeCount', num)
}, 1000)
}
}
})
// 导出给main.js使用
export default store
1.2.2. main.js
import Vue from 'vue'
import App from './App.vue'
import store from '@/store/index'
console.log(store.state.count)
Vue.config.productionTip = false
new Vue({
render: h => h(App),
store
}).$mount('#app')
1.2.3. App.vue
<template>
<div id="app">
<h1>根组件 - {{ title }} - {{ count }}</h1>
<input :value="count" @input="handleInput" type="text">
<Son1></Son1>
<hr>
<Son2></Son2>
</div>
</template>
<script>
import Son1 from './components/Son1.vue'
import Son2 from './components/Son2.vue'
import { mapState } from 'vuex'
export default {
name: 'app',
created () {
console.log(this.$store.state.count)
},
data () {
return {
}
},
methods: {
handleInput (e) {
// 1.实时获取输入框的值
const num = e.target.value
// 2.提交mutation,调用mutation函数
this.$store.commit('changeCount', num)
}
},
computed: {
...mapState(['count', 'title'])
},
components: {
Son1,
Son2
}
}
</script>
<style>
</style>
1.2.4. Son1.vue
<template>
<div class="box">
<h2>{{ $store.state.title }}</h2>
从vuex中获取的值:<label>{{ $store.state.count }}</label>
<br>
<button @click="subCount(1)">值 + 1</button>
<button @click="subCount(5)">值 + 5</button>
<button @click="subCount(10)">值 + 10</button>
<button @click="handleSub(1)">值 - 1</button>
<button @click="handleSub(5)">值 - 5</button>
<button @click="handleSub(10)">值 - 10</button>
<button @click="handleChange(34)">值 + 34</button>
<button @click="changeTitle">改标题</button>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
export default {
name: 'Son1Com',
methods: {
handleAdd (n) {
// 错误代码(vue默认不会监测,监测需要成本)
// this.$store.state.count++
// console.log(this.$store.state.count)
// 应该通过 mutation 核心概念,进行修改仓库数据
// 需要提交调用mutation
this.$store.commit('addCount', n)
},
...mapMutations(['subCount']),
changeTitle () {
this.$store.commit('changeTitle', { name: '王哲晓', newTitle: '2024加油,迎接新的开始,新的起点,新的人生' })
},
handleChange (n) {
// 调用action
// this.$store.dispatch('action名字', 额外参数)
this.$store.dispatch('changeCountAction', n)
}
}
}
</script>
<style lang="css" scoped>
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
</style>
1.2.5. Son2.vue
<template>
<div class="box">
<h2>Son2 子组件</h2>
从vuex中获取的值:<label>{{ count }}</label>
<br>
<button>值 - 1</button>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'Son2Com',
computed: {
...mapState(['count'])
}
}
</script>
<style lang="css" scoped>
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
</style>
二、mapActions
2.1. 使用方法
mapActions 是把位于actions中的方法提取了出来,映射到组件methods中,简化了actions函数。
2.2. 完整代码
我们在上面的代码基础上对Son1.vue稍做调整:
<template>
<div class="box">
<h2>{{ $store.state.title }}</h2>
从vuex中获取的值:<label>{{ $store.state.count }}</label>
<br>
<button @click="subCount(1)">值 + 1</button>
<button @click="subCount(5)">值 + 5</button>
<button @click="subCount(10)">值 + 10</button>
<button @click="handleSub(1)">值 - 1</button>
<button @click="handleSub(5)">值 - 5</button>
<button @click="handleSub(10)">值 - 10</button>
<button @click="handleChange(34)">值 + 34</button>
<button @click="changeTitle">改标题</button>
<button @click="changeCountAction(6666)">1秒钟后化神</button>
</div>
</template>
<script>
import { mapMutations, mapActions } from 'vuex'
export default {
name: 'Son1Com',
methods: {
handleAdd (n) {
// 错误代码(vue默认不会监测,监测需要成本)
// this.$store.state.count++
// console.log(this.$store.state.count)
// 应该通过 mutation 核心概念,进行修改仓库数据
// 需要提交调用mutation
this.$store.commit('addCount', n)
},
...mapMutations(['subCount']),
...mapActions(['changeCountAction']),
changeTitle () {
this.$store.commit('changeTitle', { name: '王哲晓', newTitle: '2024加油,迎接新的开始,新的起点,新的人生' })
},
handleChange (n) {
// 调用action
// this.$store.dispatch('action名字', 额外参数)
this.$store.dispatch('changeCountAction', n)
}
}
}
</script>
<style lang="css" scoped>
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
</style>
三、getters
3.1. 使用方法
除了state之外,有时我们还需要从state中派生出一些状态,这些状态是依赖state的,此时会用到getters(类似于计算属性)
例如:state 中定义了list,为1-10的数组,组件中需要显示所有大于5的数据。
1. 定义 getters
2. 访问getters
① 通过 store 访问 getters
② 通过辅助函数 mapGetters 映射
3.2. 完整代码
3.2.1. main.js
import Vue from 'vue'
import App from './App.vue'
import store from '@/store/index'
console.log(store.state.count)
Vue.config.productionTip = false
new Vue({
render: h => h(App),
store
}).$mount('#app')
3.2.2. index.js
// 存放的是vuex相关的核心代码
import Vue from 'vue'
import Vuex from 'vuex'
// 配置插件给Vue使用
Vue.use(Vuex)
// 创建仓库(空仓库)
const store = new Vuex.Store({
// 严格模式(有利于初学者,检测不规范的代码 => 上线的时候可以去掉)
strict: true,
// 1. 通过 state提供数据(所有组件可以共享)
state: {
title: '大标题',
count: 100,
list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
},
// 2. 通过 mutations 可以提供修改数据的方法
mutations: {
// 所有mutation函数,第一个参数,都是 state
addCount (state, n) {
// 修改数据
state.count += n
},
subCount (state, n) {
// 修改数据
state.count -= n
},
changeTitle (state, obj) {
state.title = obj.newTitle
},
changeCount (state, newCount) {
state.count += newCount
}
},
// 3. actions处理异步,它不能直接操作state,操作state还是需要commit mutation
actions: {
// context 上下文 (此处因为我们还未分模块,可以当成store仓库)
// context.commit('mutation名字', 额外参数)
changeCountAction (context, num) {
// 这里是setTimeout模拟异步,以后大部分场景是发请求
setTimeout(() => {
context.commit('changeCount', num)
}, 1000)
}
},
// 4. getters 类似于计算属性
getters: {
// 注意点:
// 1. 形参第一个参数,就是state
// 2. 必须有返回值,返回值就是getters的值
filterList (state) {
return state.list.filter(item => item > 5)
}
}
})
// 导出给main.js使用
export default store
3.2.3. App.vue
<template>
<div id="app">
<h1>根组件 - {{ title }} - {{ count }}</h1>
<input :value="count" @input="handleInput" type="text">
<Son1></Son1>
<hr>
<Son2></Son2>
</div>
</template>
<script>
import Son1 from './components/Son1.vue'
import Son2 from './components/Son2.vue'
import { mapState } from 'vuex'
export default {
name: 'app',
created () {
console.log(this.$store.state.count)
},
data () {
return {
}
},
methods: {
handleInput (e) {
// 1.实时获取输入框的值
const num = e.target.value
// 2.提交mutation,调用mutation函数
this.$store.commit('changeCount', num)
}
},
computed: {
...mapState(['count', 'title'])
},
components: {
Son1,
Son2
}
}
</script>
<style>
</style>
3.2.4. Son1.vue
<template>
<div class="box">
<h2>{{ $store.state.title }}</h2>
从vuex中获取的值:<label>{{ $store.state.count }}</label>
<br>
<button @click="subCount(1)">值 + 1</button>
<button @click="subCount(5)">值 + 5</button>
<button @click="subCount(10)">值 + 10</button>
<button @click="handleSub(1)">值 - 1</button>
<button @click="handleSub(5)">值 - 5</button>
<button @click="handleSub(10)">值 - 10</button>
<button @click="handleChange(34)">值 + 34</button>
<button @click="changeTitle">改标题</button>
<button @click="changeCountAction(6666)">1秒钟后化神</button>
<hr>
<div>{{ $store.state.list }}</div>
<div>{{ $store.getters.filterList }}</div>
<hr>
<div>{{ filterList }}</div>
</div>
</template>
<script>
import { mapMutations, mapActions, mapGetters } from 'vuex'
export default {
name: 'Son1Com',
computed: {
...mapGetters(['filterList'])
},
methods: {
handleAdd (n) {
// 错误代码(vue默认不会监测,监测需要成本)
// this.$store.state.count++
// console.log(this.$store.state.count)
// 应该通过 mutation 核心概念,进行修改仓库数据
// 需要提交调用mutation
this.$store.commit('addCount', n)
},
...mapMutations(['subCount']),
...mapActions(['changeCountAction']),
changeTitle () {
this.$store.commit('changeTitle', { name: '王哲晓', newTitle: '2024加油,迎接新的开始,新的起点,新的人生' })
},
handleChange (n) {
// 调用action
// this.$store.dispatch('action名字', 额外参数)
this.$store.dispatch('changeCountAction', n)
}
}
}
</script>
<style lang="css" scoped>
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
</style>
3.2.5. Son2.vue
<template>
<div class="box">
<h2>Son2 子组件</h2>
从vuex中获取的值:<label>{{ count }}</label>
<br>
<button>值 - 1</button>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'Son2Com',
computed: {
...mapState(['count'])
}
}
</script>
<style lang="css" scoped>
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
</style>