鸦杀's Blog

理解vuex

2018-09-04

用了这么久vuex,面试时也被问到很多次组件通信,没有好好出一篇博客是有点说不过去~

那就写吧~~

首先,vuex是什么?,它是类flux的状态管理的官方实现,大型应用的多组建通信的解决方案,可以帮我们处理组件之间共享状态管理的问题。

那么,flux是什么呢,它是一种架构模式,核心思想是数据和逻辑都是单向的,数据从actiondispatcher,再到store,最终到view的路线是单向不可逆的。

好了,再回到vuexvuex5大核心,分别是:

  • state,存放共享数据

  • mutation,变动state的方法,需要通过store.commit()提交变动来触发

  • getter,有点像vue中的computed属性

  • action,提交mutation的方法,可以调用store.commit(),它本身要通过store.dispatch()派发来触发。

  • module,用来分割模块,每一个模块中都可以有state、mutations、getters、actions属性,模块可以嵌套,所以也有可能有modules属性。

vuex

上图表示了vuex中的数据和逻辑流向。组件派发action,action提交mutation,mutation修改state,state修改后重新渲染组件。
其中,与后端接口的交互是放在action中的,action中可以有异步操作,但mutation中只可以有同步操作。

vuex与普通的全局对象有2点不同:

  • 1、它的状态存储是响应式的
  • 2、数据流是单向的,必须通过提交mutation显示改变

用法

vuex使用单一状态树,每个应用只包含一个store实例。
最简单的使用state的方式是引入store文件,然后在computed中通过store.state.xxx获取。

更好的方式是入口文件中使用Vue.use(Vuex),然后在创建vue实例的时候把store属性带上,这样子组件就可以通过this.$store来访问store,而不需要每次引入store文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 入口函数
import Vue from 'vue';
import App from './App';
import router from './router';
import store from './store';

Vue.config.productionTip = false;

/* eslint-disable no-new */
new Vue({
// 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
store,
el: '#app',
router,
components: { App },
template: '<App/>',
});

1
2
3
4
5
6
// 组件中
computed: {
tit() {
return this.$store.state.title;
},
},

每一个核心及它们的辅助函数,可以看官网文档的具体介绍,觉得已经很全面了,这里就不浪费笔墨了。

DEMO

vue-cli跑了一个demo,简单添加了下vuex的功能。
src目录下窗口store目录,包含以下文件

1
2
3
4
5
6
├── actions.js
├── getters.js
├── index.js
├── mutations.js
├── state.js
└── types.js

1
2
3
4
5
6
7
8
// actions.js
import * as types from './types';

export default {
[types.COUNT](context, value) {
context.commit(types.COUNT, value);
},
};
1
2
3
4
5
6
// getters.js
export default {
total(state) {
return `${state.title} - ${state.count}`;
},
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// index.js
import Vue from 'vue';
import Vuex from 'vuex';
import actions from './actions';
import getters from './getters';
import mutations from './mutations';
import state from './state';

Vue.use(Vuex);

export default new Vuex.Store({
state,
mutations,
actions,
getters,
});
1
2
3
4
5
6
7
8
9
10
11
// mutations.js
import * as types from './types';

export default {
[types.TITLE](state, value) {
state.title = value;
},
[types.COUNT](state, value) {
state.count = value;
},
};
1
2
3
4
// state.js
export default {
title: '666',
};
1
2
3
// type.js
export const TITLE = 'title';
export const COUNT = 'count';

然后在入口函数中引入store,将store注入到子组件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import Vue from 'vue';
import App from './App';
import router from './router';
import store from './store';

Vue.config.productionTip = false;

/* eslint-disable no-new */
new Vue({
store,
el: '#app',
router,
components: { App },
template: '<App/>',
});

组件中使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import * as types from '../store/types';

export default {
name: 'HelloWorld',
data() {
return {
msg: 'Welcome to Your Vue.js App',
};
},
created() {
this.$store.commit(types.TITLE, 555);
this.$store.dispatch(types.COUNT, 5);
},
computed: {
tit() {
return this.$store.state.title;
},
},
};

这里的例子中没有用到module,如果是大型应用的话,推荐使用module

Tags: vuex

扫描二维码,分享此文章