初识vuex

1.简介html

vuex是 vue官方推荐的一个状态管理器。当咱们遇到不少状态改变时,组件之间的通讯就会变得复杂,这时候vuex的强大就展示出来。vue

咱们从vuex的原理以及vuex的api两个部分介绍vuexes6

原理:vuex

vuex的核心是store对象,它承载了vue的状态管理。vuex的实现分为了2个部分,第一个部分是store的建立,以及第二部分store的挂载,而且解析store。api

vuex经过插件安装的形式来使得vue挂载vuex的store,固然这个是在vue组件的createBefore阶段实现的。随后Vuex将它直接挂载到 $options.$store 以供使用vue使用。数组

对于vuex的属性,Vuex 会将 vuex 属性解构成 getters 和 actions。并将 getters 的每一个属性都挂载 vm 下(有可能被组件的 $options.data() 的属性覆盖),同时定义每一个值的 getter 方法,但并不会定义 setter 方法,这是由于根据 Vuex 的设计是不容许开发者直接在组件内更改 store.state,而对数据的改动要经过提交 mutation。Vuex 实际上将 vm.vuex.getter 内的属性看成当前 vm 的计算属性来处理。和计算属性的区别是计算属性依赖计算的是 vm.$options.data 内的值,而 vm.vuex.getter 的属性依赖计算的是 store._vm.$options.data。这样全部组件的渲染都将均可以直接从状态树拿数据来渲染 UI 。promise

全部的组件均可以和vuex的状态树进行数据交互。可是不容许直接改变状态树的状态,应该用vuex的mutations来提交状态的改变。vuex会将actions内的方法绑定到vue的$options.methods下,它们与vue中定义的方法并无区别。而 actions 内的方法将经过 dispatch 触发 mutations 来更新全局状态,actions方法与mutations的区别是,mutations改变state而且必须是同步改变,而actions能够做为异步提交的方法,dispatch 能够接收一个promise,而且返回一个promise。异步

2.API:函数

state:在vue中引入store对象,在子组件中经过this.$store来访问vuex中状态,而且咱们最好在vue的computed中获取vuex的状态。this

mapState:这是一个语法糖,能够快捷的获取更多的state。

接受一个object参数:

// 在单独构建的版本中辅助函数为 Vuex.mapState
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
    }
  })
}

当计算属性的名称和节点名称相同时,也能够接受一个数组对象。

computed: mapState([
  // 映射 this.count 为 store.state.count
  'count'
])

对象展开:合成最终的computed属性

computed: {
  localComputed () { /* ... */ },
  // 使用对象展开运算符将此对象混入到外部对象中
  ...mapState({
    // ...
  })
}

getter:store的计算属性,在获取数据的时候,咱们能够经过getter进行数据的操做,在相同地方用到的数据操做就不须要写一个公用的处理函数。它接受2个参数,state和getters。

getters: {
  // ...
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  }
}
store.getters.doneTodosCount // -> 1

mapGetters:

export default {
  // ...
  computed: {
  // 使用对象展开运算符将 getters 混入 computed 对象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  }
}

或者

mapGetters({
  // 映射 this.doneCount 为 store.getters.doneTodosCount
  doneCount: 'doneTodosCount'
})

 

mutations:vuex提交状态的惟一方式。mutations更像一个事件监听器,当vue中commit了信息以后,相应的mutation才会执行相应的回掉函数。它接受2个参数,state和object。

由于vue是响应式的,因此mutations也应该遵照vue的动态绑定,因此在须要使用mutations前,尽可能初始化。或者是添加时使用vue.set(obj,'new obj', 'value')或者以新运算符state.obj = { ...state.obj, newProp: 123 }

mutations必须是同步函数

组件中提交mutations:

import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    ...mapMutations([
      'increment' // 映射 this.increment() 为 this.$store.commit('increment')
    ]),
    ...mapMutations({
      add: 'increment' // 映射 this.add() 为 this.$store.commit('increment')
    })
  }
}

 

actions: actions提交的是mutations,由于mutations是必须为同步状态,actions就提供了一种异步的形式提交mutations,咱们能够在active中去作异步处理,而且提交mutation。它接受一个context参数,这个参数具备store对象相同属性和方法,可是并非store自己。

actions: {
    increment (context) {
      context.commit('increment')
    }
  }

//或者 使用解值
actions: {
  increment ({ commit }) {
    commit('increment')
  }
}

actions以dispatch来分发

// 以载荷形式分发
store.dispatch('incrementAsync', {
  amount: 10
})

// 以对象形式分发
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

组合的actions:

store.dispatch 能够处理被触发的action的回调函数返回的Promise,而且store.dispatch仍旧返回Promise

actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  }
}
// 能够这样触发
//
一个  在不一样模块中能够触发多个 action 函数。在这种状况下,只有当全部触发函数完成后,返回的 Promise 才会执行。
store.dispatch('actionA').then(() => {
  // ... store.dispatch
})

// 也能够这样子触发
actions: {
// ...
  actionB ({ dispatch, commit }) {
    return dispatch('actionA').then(() => {
      commit('someOtherMutation')
    })
  }
}


 

modules:

Vuex 容许咱们将 store 分割到模块(module)。每一个模块拥有本身的 state、mutation、action、getters、甚至是嵌套子模块——从上至下进行相似的分割。

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 的状态

模块的局部状态

对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态。

const moduleA = {
  state: { count: 0 },
  mutations: {
    increment (state) {
      // state 模块的局部状态
      state.count++
    }
  },

  getters: {
    doubleCount (state) {
      return state.count * 2
    }
  }
}

对于模块内部的 action,context.state 是局部状态,根节点的状态是 context.rootState。

const moduleA = {
  // ...
  actions: {
    incrementIfOddOnRootSum ({ state, commit, rootState }) {
      if ((state.count + rootState.count) % 2 === 1) {
        commit('increment')
      }
    }
  }
}

 

对于模块内部的 getter,根节点状态会做为第三个参数。

 

const moduleA = {
  // ...
  getters: {
    sumWithRootCount (state, getters, rootState) {
      return state.count + rootState.count
    }
  }
}

命名空间:

模块内部的 action、mutation、和 getter 如今仍然注册在全局命名空间——这样保证了多个模块可以响应同一 mutation 或 action。你能够经过添加前缀或后缀的方式隔离各模块,以免名称冲突。你也可能但愿写出一个可复用的模块,其使用环境不可控。例如,咱们想建立一个 todos 模块:

// types.js

// 定义 getter、action、和 mutation 的名称为常量,以模块名 `todos` 为前缀
export const DONE_COUNT = 'todos/DONE_COUNT'
export const FETCH_ALL = 'todos/FETCH_ALL'
export const TOGGLE_DONE = 'todos/TOGGLE_DONE'
// modules/todos.js
import * as types from '../types'

// 使用添加了前缀的名称定义 getter、action 和 mutation
const todosModule = {
  state: { todos: [] },

  getters: {
    [types.DONE_COUNT] (state) {
      // ...
    }
  },

  actions: {
    [types.FETCH_ALL] (context, payload) {
      // ...
    }
  },

  mutations: {
    [types.TOGGLE_DONE] (state, payload) {
      // ...
    }
  }
}

咱们也能够运用es6的新方法,symbol作命名;

须要了解更多关于symbol的信息,请移步阮一峰老师的ES6

 

参考文献:

vuex文档

为何 Vuex 比 Redux 更适合 Vue.js

相关文章
相关标签/搜索