vuex相关汇总
# 状态管理基本
# vuex是什么
Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
# 怎么使用vuex
第一步安装
npm install vuex -S
第二步创建store
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
//不是在生产环境debug为true
const debug = process.env.NODE_ENV !== 'production';
//创建Vuex实例对象
const store = new Vuex.Store({
strict:debug,//在不是生产环境下都开启严格模式
state:{
},
getters:{
},
mutations:{
},
actions:{
}
})
export default store;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
第三步注入vuex
import Vue from 'vue';
import App from './App.vue';
import store from './store';
const vm = new Vue({
store:store,
render: h => h(App)
}).$mount('#app')
2
3
4
5
6
7
# vuex中有几个核心属性,分别是什么?
一共有5个核心属性,分别是:
- state 唯一数据源,Vue 实例中的 data 遵循相同的规则
- getters 可以认为是 store 的计算属性,就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。Getter 会暴露为 store.getters 对象,你可以以属性的形式访问这些值.
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
}
})
store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
2
3
4
5
6
7
8
9
10
11
12
13
14
- mutation 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation,非常类似于事件,通过store.commit 方法触发
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
state.count++ // 变更状态
}
}
})
store.commit('increment')
2
3
4
5
6
7
8
9
10
11
- action Action 类似于 mutation,不同在于Action 提交的是 mutation,而不是直接变更状态,Action 可以包含任意异步操作
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- module 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 你使用过 Vuex 吗?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。
(1)Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
(2)改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。
主要包括以下几个模块:
- State:定义了应用状态的数据结构,可以在这里设置默认的初始状态。
- Getter:允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。
- Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。
- Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
- Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。
# Vuex 的原理以及自己的理解
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。
- Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
- 改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。
Vuex为Vue Components建立起了一个完整的生态圈,包括开发中的API调用一环。
(1)核心流程中的主要功能:
- Vue Components 是 vue 组件,组件会触发(dispatch)一些事件或动作,也就是图中的 Actions;
- 在组件中发出的动作,肯定是想获取或者改变数据的,但是在 vuex 中,数据是集中管理的,我们不能直接去更改数据,所以会把这个动作提交(Commit)到 Mutations 中;
- 然后 Mutations 就去改变(Mutate)State 中的数据;
- 当 State 中的数据被改变之后,就会重新渲染(Render)到 Vue Components 中去,组件展示更新后的数据,完成一个流程。
(2)各模块在核心流程中的主要功能:
Vue Components
∶ Vue组件。HTML页面上,负责接收用户操作等交互行为,执行dispatch方法触发对应action进行回应。dispatch
∶操作行为触发方法,是唯一能执行action的方法。actions
∶ 操作行为处理模块。负责处理Vue Components接收到的所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发。向后台API请求的操作就在这个模块中进行,包括触发其他action以及提交mutation的操作。该模块提供了Promise的封装,以支持action的链式触发。commit
∶状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。mutations
∶状态改变操作方法。是Vuex修改state的唯一推荐方法,其他修改方式在严格模式下将会报错。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些hook暴露出来,以进行state的监控等。state
∶ 页面状态管理容器对象。集中存储Vuecomponents中data对象的零散数据,全局唯一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用Vue的细粒度数据响应机制来进行高效的状态更新。getters
∶ state对象读取方法。图中没有单独列出该模块,应该被包含在了render中,Vue Components通过该方法读取全局state对象。
# mutation和action有什么区别【要点】
从下面三个方面说;
action 提交的是 mutation,而不是直接变更状态。mutation可以直接变更状态;action 可以包含任意异步操作。mutation只能是同步操作
提交方式不同
- mutation是用
this.$store.commit('SET_NUMBER',10)
来提交; - action 是用
this.$store.dispatch('ACTION_NAME',data)
来提交;
- mutation是用
接收参数不同,mutation第一个参数是state,而action第一个参数是context, [store自己],其包含了
{
state, // 等同于 `store.state`,若在模块中则为局部状态
rootState, // 等同于 `store.state`,只存在于模块中
commit, // 等同于 `store.commit`
dispatch, // 等同于 `store.dispatch`
getters, // 等同于 `store.getters`
rootGetters // 等同于 `store.getters`,只存在于模块中
}
2
3
4
5
6
7
8
示范:
mutations: {
SET_TOKEN: (state, token) => {
state.token = token
},
},
actions: {
Login ({ commit }, userInfo) {
return new Promise((resolve, reject) => {
login(userInfo).then(response => {
const result = response.result
storage.set(ACCESS_TOKEN, result.token, 7 * 24 * 60 * 60 * 1000)
commit('SET_TOKEN', result.token)
resolve()
}).catch(error => {
reject(error)
})
})
},
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Vuex中action和mutation的区别
mutation中的操作是一系列的同步函数,用于修改state中的变量的的状态。当使用vuex时需要通过commit来提交我们需要操作的内容。mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
state.count++ // 变更状态
}
}
})
2
3
4
5
6
7
8
9
10
# ajax请求代码应该写在组件的methods中还是vuex的actions中
如果请求来的数据是不是要被其他组件公用,仅仅在请求的组件内使用,就不需要放入vuex 的state里。
如果被其他地方复用,这个很大几率上是需要的,如果需要,请将请求放入action里,方便复用。
# 从vuex中获取的数据能直接更改吗?
从vuex中取的数据,不能直接更改,需要浅拷贝对象之后更改,否则报错;
# vuex中的数据在页面刷新后数据消失
用sessionstorage 或者 localstorage 存储数据
- 存储: sessionStorage.setItem( '名', JSON.stringify(值) )
- 使用: sessionStorage.getItem('名') ---得到的值为字符串类型,用JSON.parse()去引号;
也可以引入插件vuex-persist,使用方法如下:
- 安装
npm install --save vuex-persist
or
yarn add vuex-persist
2
3
引入
import VuexPersistence from 'vuex-persist'
先创建一个对象并进行配置
const vuexLocal = new VuexPersistence({
storage: window.localStorage
})
2
3
- 引入进vuex插件
const store = new Vuex.Store({
state: { ... },
mutations: { ... },
actions: { ... },
plugins: [vuexLocal.plugin]
})
2
3
4
5
6
通过以上设置,在图3中各个页面之间跳转,如果刷新某个视图,数据并不会丢失,依然存在,并且不需要在每个 mutations 中手动存取 storage 。
# 自己实现plugin插件
实现VuexPersistence
和logger
class VuexPersistence {
constructor({ storage }) {
this.storage = storage;
this.localName = "VUEX-MY";
}
plugin = (store) => {
let localState = JSON.parse(this.storage.getItem(this.localName));
if (localState) store.replaceState(localState);
store.subscribe((mutationName, state) => {
// 这里需要做一个节流 throttle lodash
this.storage.setItem(this.localName, JSON.stringify(state));
});
};
}
// 自己实现logger插件
const logger = () => (store) => {
let prevState = JSON.stringify(store.state);
store.subscribe((mutationName, state) => {
// 监听变化的 ,每次数据变化都会执行此方法 commit 的时候会执行此方法
console.log("prev" + prevState);
console.log(mutationName);
prevState = JSON.stringify(state);
console.log("next", prevState);
});
};
const vuexLocal = new VuexPersistence({
storage: window.localStorage,
});
Vue.use(Vuex); // 使用这个插件 内部会调用Vuex中的install方法
const store = new Vuex.Store({
// strict: true,
plugins: [
// 插件从上到下执行
vuexLocal.plugin, // 放在这里 插件默认就会显执行一次
logger(),
],
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# Vuex的严格模式是什么,有什么作用,怎么开启?
**在严格模式下,无论何时发生了状态变更且不是由mutation函数引起的,将会抛出错误。**这能保证所有的状态变更都能被调试工具跟踪到。
在Vuex.Store 构造器选项中开启,如下
const store = new Vuex.Store({
strict:true,
})
2
3
# 怎么在组件中批量使用Vuex的getter属性
使用mapGetters辅助函数, 利用对象展开运算符将getter混入computed 对象中
import {mapGetters} from 'vuex'
export default{
computed:{
...mapGetters(['total','discountTotal'])
}
}
2
3
4
5
6
# 组件中重复使用mutation
使用mapMutations辅助函数,在组件中这么使用
import { mapMutations } from 'vuex'
methods:{
...mapMutations({
setNumber:'SET_NUMBER',
})
}
computed: {
// 直接取出状态中的结果
...mapState(['lesson']),
// 给状态起名字
...mapState({lesson1:'lesson'}),
// 通过函数的方式获取结果
...mapState({lesson2:state=>state.lesson})
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
然后调用this.setNumber(10)相当调用this.$store.commit('SET_NUMBER',10);
export * from './helpers';
import {createNamespacedHelpers} from 'vuex';
//import {mapState,mapGetters, mapMutations, mapActions} from 'vuex';
let {mapState as mapState1 ,mapGetters} = createNamespacedHelpers('samy');
export default {
computed: {
// 直接取出状态中的结果
...mapState(['lesson']),
// 给状态起名字
...mapState({lesson1:'lesson'}),
// 通过函数的方式获取结果
...mapState({lesson2:state=>state.lesson})
// getName(){
// return this.$store.getters.getLessonName
// }
...mapGetters(['getLessonName'])//通过辅助函数可以简写很多;
},
methods: {
//this.$store.dispatch('SET_LESSON_NAME');
...mapMutations(['SET_LESSON_NAME']), //mapMutations简化方法;
...mapActions(['Login', 'Logout']),
changeName(){
this['SET_LESSON_NAME']({number:10});
},
stepCaptchaCancel () {
this.Logout().then(() => {
this.loginBtn = false
this.stepCaptchaVisible = false
})
},
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 在v-model上怎么用Vuex中state的值?
需要通过computed计算属性来转换。 get/set处理
<input v-model="message">
// ...
computed: {
message: {
get () {
return this.$store.state.message
},
set (value) {
this.$store.commit('updateMessage', value)
}
}
}
2
3
4
5
6
7
8
9
10
11
12