本文为课程 vuex深入浅出 的学习总结与记录;同时参照了vuex官方文档。
文中demo的代码可参考:我的码云
一、概念
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
-
不使用vuex的数据流:
image.png -
使用vuex进行状态维护:
image.png
二、在项目中使用vuex
可以通过以下步骤引入vuex
:
- 安装:
npm install vuex --save
- 创建
store
目录,用来存放所有状态。大型项目的目录结构可能如下所示:
image.png
在此我们只创建一个store.js
文件作为示例:
state中存放的是唯一数据源
import Vue from 'vue'
import Vuex from 'vuex';
Vue.use(Vuex)
export const store = new Vuex.Store({ // 注意Store的S大写
state: {
data1: ...,
data2: ...
...
}
})
- 在
main.js
中添加如下代码:
import {store} from '../store/index'
new Vue({
...
store,
...
})
三、核心概念介绍
原课程是以小demo的形式讲解vuex
,在此依同样方法做以记录。
此demo有两个组件listOne.vue
和listTwo.vue
,App.vue
为主组件。
最终效果和初始代码(省略样式)如下:
store.js:
import Vue from 'vue'
import Vuex from 'vuex';
Vue.use(Vuex)
export const store = new Vuex.Store({ // 注意Store的S大写
state: {
productList: [
{name: 'goods 1',price: 100},
{name: 'goods 2',price: 200},
{name: 'goods 3',price: 300},
{name: 'goods 3',price: 400}
]
}
})
App.vue:
<template>
<div>
<list-one/>
<list-two/>
</div>
</template>
<script>
import listOne from './components/listOne.vue';
import listTwo from './components/listTwo.vue';
export default {
name: 'App',
components: {
listOne, listTwo
}
}
</script>
listOne.vue:
<template>
<div class="list-one">
<h1>list one</h1>
<ul>
<li v-for="(product, index) in productList" :key=index>
<p>名称:{{product.name}}</p>
<p>价格:{{product.price}}</p>
</li>
</ul>
<button>降价</button>
<button>异步降价</button>
</div>
</template>
<script>
export default {
data() {
productList: this.$store.state.productList // 获取store.js > state > productList
}
}
</script>
listTwo.vue:
<template>
<div class="list-two">
<h1>list two</h1>
<ul>
<li v-for="(product, index) in getProductList" :key=index>
<p>名称:{{product.name}}</p>
<p>价格:{{product.price}}</p>
</li>
</ul>
</div>
</template>
<script>
import {mapGetters} from 'vuex'
export default {
data() {
productList: this.$store.state.productList
}
}
</script>
核心概念1:state
-
state
是vuex
的唯一数据源,是所有组件的公共data
。中上述代码中,我们已经将两个组件的公共数据存入state
。在组件中,使用this.$store.state.product
获取state
中的数据。 - 如果需要获取多个
state
,可使用...mapState
辅助函数。如下:
import {mapState} from 'vuex;
...
computed: {
...mapState([
'productList',
'...'
])
}
此时组件中修改如下:
<li v-for="(product, index) in productList" :key=index>
核心概念2:getters
-
getters
用于从state
中派生出一些状态,例如对列表进行过滤等。可以将getters
理解为计算属性computed
,getter
的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。 -
getters
接受state
作为其第一个参数 - 这时我们可以在
store.js
中添加一个getter
属性:saleProducts
,用于将商品价格除以2。
// store.js:
import Vue from 'vue'
import Vuex from 'vuex';
Vue.use(Vuex)
export const store = new Vuex.Store({
state: {
productList: [
{name: 'goods 1',price: 100},
{name: 'goods 2',price: 200},
{name: 'goods 3',price: 300},
{name: 'goods 3',price: 400}
]
},
getters: {
getSaledPrice: (state) => {
let saleProduct = state.productList.map((item) => {
return {
name: '**' + item.name + '**',
price: item.price / 2
}
})
return saleProduct;
}
}
})
将listOne.vue
中的productList
的值更换为this.$store.getters.getSaledPrice
:
// listOne.vue
export default {
data () {
return {
productList : this.$store.getters.getSaledPrice
}
}
}
此时效果如下:(注意list one
部分名称和价格的变动)
- 如果需要使用多个
getters
,可使用...mapGetters
辅助函数。如下:
computed: {
...mapGetters:([
'getSaledPrice',
...
])
}
核心概念3:mutation
- 更改
vuex
的store
中的状态的唯一方法是提交mutation
。vuex
中的mutation
类似于事件:每个mutation
都有一个字符串的事件类型和一个回调函数。这个回调函数就是我们实际进行状态更改的地方,并且它会接受state
作为第一个参数(payload
为第二个参数,也就是自定义参数)。 - 在此我们给
store
添加一个mutation
属性reducePrice
,用于将商品价格减少payload
:
// store.js
mutations: {
reducePrice: (state, payload) => {
return state.productList.forEach((product) => {
product.price -= payload;
})
}
}
// listOne.vue
methods: {
reducePrice(){
this.$store.commit('reducePrice', 4)
}
}
点击降价按钮,可以发现价格发生变化:
image.png
- 或使用
mapMutations
辅助对象:
// listOne.vue
<template>
...
<button @click="reducePrice(4)">降价</button>
...
</template>
<script>
.....
methons: {
...mapMutations([
'reducePrice'
])
}
.....
</script>
核心概念4:action
-
action
类似于mutation
,不同之处在于:
-
action
提交的是mutation
,而不是直接变更状态。 -
action
可以包含异步操作,而mutation
不行。 -
actions
中的回调函数的第一个参数是context
, 是一个与store
实例具有相同属性和方法的对象. -
action
通过store.dispatch
方法触发,mutation
通过store.commit
方法提交。
- 在此我们添加一个
action
属性,用来进行异步降价操作(每隔2秒后改变价格)
// store.js
actions: { // 提交的是mutation,可以包含异步操作
reducePriceAsync: (context, payload) => {
setTimeout(()=> {
context.commit('reducePrice', payload); // reducePrice为上一步mutation中的属性
},2000)
}
}
methods: {
reducePriceAsync(){
this.$store.dispatch('reducePriceAsync', 2)
},
}
或使用mapActions
辅助对象:
// listOne.js
<template>
...
<button @click="reducePriceAsync(4)">异步降价</button>
...
</template>
<script>
.....
methons: {
...mapActions([
'resducePriceAsync'
])
}
.....
</script>
核心概念5:module
image.png由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。
网友评论