Vuex是vue的状态管理器,它采用 集中式的存储管理方式管理组件的全部状态。并以必定的规则来保证状态以一种 可预测的方向发生变化~~Vuex产生的原因html
new Vue({ // state data () { return { count: 0 } }, // view template: ` <div>{{ count }}</div> `, // actions methods: { increment () { this.count++ } } })
上面这个简单的实例:包含了state、view视图、actions操做。vue
三者以一种单向数据流的形式在运行着。可是若是咱们碰到了多组件须要共享状态的时候,单向数据流就不大行了~~面试
遇到了种种问题,咱们会有疑问,为何不使用一种全局单例模式对咱们的状态进行一个全局的统一管理呢,这样咱们的组件树就成为了一个大的视图,无论咱们在树的任何位置,咱们均可以对状态进行获取和action操做。这样将使得咱们的项目可以更好的维护于发展。ajax
这是vuex的内部核心思想,它还借鉴了redux、flux等。vue高度契合vue的细粒度的数据响应机制,来实现高效的状态管理。vuex
import Vue from "vue"; import Vuex from "vuex"; Vue.use(Vuex); export default new Vuex.Store({ state: { count: 1 // 计数 }, getters: { getCount(state) { return state.count > 120 ? 120 : state.count; } }, mutations: { add(state, num) { return state.count = state.count + num; }, de(state, payload) { state.count-=payload.n; } }, actions: { add(context) { setTimeout( ()=>{ context.commit('add', 100 ) }, 1000) } } });
<template> <div id="app"> <span>{{$store.state.count}}</span> <button @click="add">添加</button> <button @click="de">减小</button> </div> </template> <script> export default { name: "APP", methods: { add() { // this.$store.commit("add", 10) this.$store.dispatch('add'); }, de() { this.$store.commit("de", { n: 4 }) } } }; </script>
上面实现了一个简单的例子;redux
答:有五种,分别是 State
、 Getter
、Mutation
、Action
、 Module
;promise
state是整个Vuex的核心,这里咱们使用的是一个单一状态树,也就是惟一数据源,这里跟module并不冲突。一个组件树共享一个store。缓存
vuex的状态是响应式的,从 store 实例中读取状态最简单的方法就是在计算属性中返回某个状态app
computed: { count() { return this.$store.state.count } },
计算属性是依赖响应,基于依赖进行计算,当它的依赖发生了变化的时候,才会从新计算咱们的返回值。异步
由于咱们的Vuex会被全部组件去使用,若是咱们频繁的导入显得不是很合理,Vue为咱们提供了机制能够从根组件注入到每个自组件中。
new Vue({ router, store, render: h => h(App) }).$mount("#app");
同时vuex为咱们提供了语法糖,方便咱们去批量获取状态。
import { mapState } from 'vuex' export default { // ... computed: mapState({ // 箭头函数可以使代码更简练 count: state => state.count, // 传字符串参数 'count' 等同于 `state => state.count` countAlias: 'count', // 为了可以使用 `this` 获取局部状态,必须使用常规函数 countPlusLocalState (state) { return state.count + this.localCount } }) }
咱们还能够更简洁,可是要求咱们的属性和store中的一致
computed: mapState([ // 映射 this.count 为 store.state.count 'count' ])
可是若是咱们还有其余的计算属性呢,咱们可使用...扩展运算符混入。
computed: { localComputed () { /* ... */ }, // 使用对象展开运算符将此对象混入到外部对象中 ...mapState({ // ... }) }
state:惟一性、响应式、获取用计算属性computed。 语法糖:mapState。
getter跟计算属性有点相似,它主要解决什么问题呢?
当咱们想要对某一个状态列表筛选的时候,咱们能够在computed中进行筛选,可是若是咱们多个组件都使用呢,咱们是否是得每一个组件都复制一份呢,显然不合理了,所以vuex容许咱们在vuex内去抽离一个筛选或者处理的公共方法。这样咱们就没必要要每次都重写一遍了。
getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) } } getters: { getCount(state) { return state.count > 120 ? 120 : state.count; } },
Getter 也能够接受其余 getter 做为第二个参数:
getters: { // ... doneTodosCount: (state, getters) => { return getters.doneTodos.length } }
使用:
computed: { doneTodosCount () { return this.$store.getters.doneTodosCount } }
一样vuex也提供了语法糖:
import { mapGetters } from 'vuex' export default { // ... computed: { // 使用对象展开运算符将 getter 混入 computed 对象中 ...mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ]) } }
同时咱们还能够给getter去传递参数
getters: { // ... getTodoById: (state) => (id) => { return state.todos.find(todo => todo.id === id) } }
注意,getter 在经过方法访问时,每次都会去进行调用,而不会缓存结果。
本人理解getter就是对状态的一个预约义处理和筛选,复用性,可预测性好。
vuex规定了咱们状态的惟一改变方式就是经过提交mutation来更改。每个mutation都有一个type类型表示咱们操做的类型,还有一个handler用来标明咱们的具体操做过程。
最简单的形式就是:
mutations: { add(state, num) { return state.count = state.count + num; }, de(state, payload) { state.count-=payload.n; } }, // 调用执行 this.$store.commit("add", 10) this.$store.commit("de", { n: 4 })
咱们还可使用对象风格的方式提交:
this.$store.commit({ type: 'add', n: 4 }) // 这种风格会把整个对象做为载荷传递过去。
注意点:
当须要在对象上添加新属性时,你应该 一、使用 Vue.set(obj, 'newProp', 123), 或者 二、以新对象替换老对象。state.obj = { ...state.obj, newProp: 123 }
可是一般咱们会使用一个字符串常量来代替咱们的mutation事件类型。
const store = new Vuex.Store({ state: { ... }, mutations: { // 咱们可使用 ES2015 风格的计算属性命名功能来使用一个常量做为函数名 [SOME_MUTATION] (state) { // mutate state } } })
还须要注意的是,mutation的操做必须是同步的,异步执行会单独放在action中执行。缘由实际上是异步操做咱们不知道如何执行完,若是咱们执行了两个mutation,咱们不知道哪一个先执行完,因此对于咱们本身也不友好,对于开发工具也很差跟踪。
import { mapMutations } from 'vuex' export default { // ... methods: { ...mapMutations([ 'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')` // `mapMutations` 也支持载荷: 'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)` ]), ...mapMutations({ add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')` }) } }
有了语法糖就不要咱们每次都显示性的写commit了。
总之:mutation就是对应咱们用户的一些行为,mutation是惟一修改store中状态的办法。咱们须要commit来同步提交。mutation 都是同步事务~~
Action跟咱们的mutation相似,可是有两个特色:
一、内部能够书写异步代码 二、内部操做的不是state,而是经过一个与 store 实例具备相同方法和属性的 context 对象。一般是commit 提交 mutation。
注意这里的context不是store,而是一个相似的对象。
actions: { incrementAsync ({ commit }) { setTimeout(() => { commit('increment') }, 1000) } } // 经过dispathc来触发 store.dispatch('increment')
固然它也有语法糖:
import { mapActions } from 'vuex' export default { // ... methods: { ...mapActions([ 'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')` // `mapActions` 也支持载荷: 'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)` ]), ...mapActions({ add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')` }) } }
const actions = { asyncInCrement({ commit }, n){ return new Promise(resolve => { setTimeout(() => { commit(types.TEST_INCREMENT, n); resolve(); },3000) }) } }
这种形式咱们能够在mutation提交以后经过.then拿到通知,去作一些咱们要作的事情。
因为使用单一状态树,应用的全部状态会集中到一个比较大的对象。当应用变得很是复杂时,store 对象就有可能变得至关臃肿。为了解决以上问题,Vuex 容许咱们将 store 分割成模块(module)。每一个模块拥有本身的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行一样方式的分割:
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 的状态
一、state是vuex的核心,咱们常称为是仓库store,或者是组件状态树。
二、它是惟一数据源。咱们的全局公共状态都防止在这个state对象中了。
三、state是响应式的。一般咱们会在组件的computed中引入咱们想要使用的state或者getters
一、getters特性咱们能够理解为它就是state中的计算属性,一般用于对咱们的state的筛选和处理
二、咱们一般习惯在组件中使用state的时候就使用咱们自定义的getters
三、getters不是必定要使用,它为了防止咱们在组件中写冗余的state处理计算属性。
一、mutation是惟一修改state的方法,且必须是同步事物
一、Action跟mutation相似,可是Action中容许你写异步代码
二、Action中处理的不是state,而是提交mutation
一、若是请求来的数据是否是要被其余组件公用,仅仅在请求的组件内使用,就不须要放入vuex 的state里。二、若是被其余地方复用,这个很大概率上是须要的,若是须要,请将请求放入action里,方便复用,并包装成promise返回,