# vuex 状态管理

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。
Vuex 官方文档 (opens new window)

# 说明

框架已内置vuex状态管理,在 .dnvue/vuex 目录下,使用vuex模块(module) (opens new window)形式。实现自动注册使用。
将vuex模块中store的js文件放入 .dnvue/vuex/ 目录下即可, vuex 目录下的所有js文件将全部自动扫描全局注册挂载。

自动注册挂载的别名为JS文件名称

┌─根目录
├───.dnvue
|     ├─common
|     └─vuex
|       ├─index.js       //index模块store的js
|       └─xxx.js       //xxx模块store的js
├───pages 
├───static 
├───uni_modules
├───App.vue
├───main.js
├───manifest.json 
├───pages.json  
└───uni.scss

# 调用方式

Vuex 官方文档 (opens new window)中的Module (opens new window)模块的使用方式一致,详细使用请阅读Vuex 官方文档 Module模块 (opens new window)

注意

框架中的 vuex 使用模块(module)形式,自动注册挂载的别名为JS文件名称,以下的示例中均以vuex中index.js文件演示

# State

单一状态树

// state
const state = () => ({
	count: 1
})

页面调用

this.$store.state.index.count  // -> 1

mapState 辅助函数
当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性,让你少按几次键:

// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'

export default {
  // ...
  computed: mapState({
    // 箭头函数可使代码更简练
    count: state => state.index.count,
    // 为了能够使用 `this` 获取局部状态,必须使用常规函数
    countPlusLocalState (state) {
      return state.index.count + this.localCount
    }
  })
}

# Mutation

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

// state
const state = () => ({
	count: 1
})
// mutations
const mutations = {
	increment (state) {
	    // 变更状态
	    state.count++
	}
}

Mutations 通过 this.$store.commit 方法触发:

this.$store.commit('index/increment')

mapMutations 辅助函数
使用 mapMutations 辅助函数将组件中的 methods 映射为 this.$store.commit 调用(需要在根节点注入 store)

import { mapMutations } from 'vuex'

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

# Action

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。
// state
const state = () => ({
	count: 0
})
// mutations
const mutations = {
	increment (state) {
	      state.count++
	}
}
// actions
const actions = {
	increment (context) {
	      context.commit('increment')
	}
}

实践中,我们会经常用到 ES2015 的 参数解构 (opens new window)来简化代码(特别是我们需要调用 commit 很多次的时候):

// actions
const actions = {
	increment ({ commit }) {
	    commit('increment')
	}
}

Action 通过 this.$store.dispatch 方法触发:

this.$store.dispatch('index/increment')

乍一眼看上去感觉多此一举,我们直接分发 mutation 岂不更方便?实际上并非如此,还记得 mutation 必须同步执行这个限制么?Action 就不受约束!我们可以在 action 内部执行异步操作:

// actions
const actions = {
	incrementAsync ({ commit }) {
	  setTimeout(() => {
	    commit('increment')
	  }, 1000)
	}
}

Actions 支持同样的载荷方式和对象方式进行分发:

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

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

mapActions 辅助函数
使用 mapActions 辅助函数将组件的 methods 映射为 this.$store.dispatch 调用(需要先在根节点注入 store)

import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions('index',[
      'increment' // 将 `this.increment()` 映射为 `this.$store.dispatch('index/increment')`
    ]),
    ...mapActions({
      add: 'index/increment' // 将 `this.add()` 映射为 `this.$store.dispatch('index/increment')`
    })
  }
}

# Getter

有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数:

// state
const state = () => ({
	todos: [
	      { id: 1, text: '...', done: true },
	      { id: 2, text: '...', done: false }
	    ]
})
// getters
const getters = {
	doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }
}

通过属性访问

this.$store.getters['index/doneTodos'] // -> [{ id: 1, text: '...', done: true }]

Getter 也可以接受其他 getter 作为第二个参数

// getters
const getters = {
	doneTodosCount: (state, getters) => {
	    return getters.doneTodos.length
	}
}
this.$store.getters['index/doneTodosCount'] // -> 1

我们可以很容易地在任何组件中使用它

computed: {
  doneTodosCount () {
    return this.$store.getters['index/doneTodosCount']
  }
}

mapGetters 辅助函数
mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:

import { mapGetters } from 'vuex'

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

# vuex中js文件规范示例

// state
const state = () => ({
	
})

// mutations
const mutations = {
	
}

// actions
const actions = {

}

// getters
const getters = {

}

export default {
	namespaced: true,
	state,
	getters,
	actions,
	mutations
}

# 单独JS中引用vuex

使用场景:在单独的js中引用vuex,使用以下方式即可。

import Vue from 'vue';
const dnvue = new Vue();

使用方式

// state
dnvue.$store.state.xxx
// mutations
dnvue.$store.commit('xxx')
// action 
dnvue.$store.dispatch('xxx')
// getter
dnvue.$store.getters['xxx']