
用于多组件共享状态,如果不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果应用够简单,您最好不要使用 Vuex。可使用简单Bus总线的方式来管理共享的数据详见(http://www.cnblogs.com/fanlinqiang/p/7756566.html)。但是,如果您需要构建是一个中大型单页应用,vuex可以更好地在组件外部管理状态
引入:
src/store/index.js
import Vue from ‘vue‘ import Vuex from ‘vuex‘ import createLogger from ‘vuex/dist/logger‘ Vue.use(Vuex) const store = new Vuex.Store({ plugins: [createLogger()] state: { count: 0, todos: [ { id: 1, text: ‘...‘, done: true }, { id: 2, text: ‘...‘, done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) }, doneTodosCount: (state, getters) => { //Getter 也可以接受其他 getter 作为第二个参数 return getters.doneTodos.length }, getTodoById: (state) => (id) => { //getter 返回一个函数来实现给 getter 传参 return state.todos.find(todo => todo.id === id) } }, mutations: { //mutation 必须同步执行,为解决这个问题我们引入了action increment (state, payload) { //store.commit 传入额外的参数,即 mutation 的 载荷(payload) state.count += payload.amount } }, actions: { //Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象, //因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。 increment (context) { context.commit(‘increment‘) }, increment ({ commit }) { //es6解构 commit(‘increment‘) }, incrementAsync ({ commit }) { setTimeout(() => { commit(‘increment‘) }, 1000) }, //store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise actionA ({ commit }) { return new Promise((resolve, reject) => { setTimeout(() => { commit(‘someMutation‘) resolve() }, 1000) }) }, actionB ({ dispatch, commit }) { return dispatch(‘actionA‘).then(() => { commit(‘someOtherMutation‘) }) } // 假设 getData() 和 getOtherData() 返回的是 Promise async actionA ({ commit }) { commit(‘gotData‘, await getData()) }, async actionB ({ dispatch, commit }) { await dispatch(‘actionA‘) // 等待 actionA 完成 commit(‘gotOtherData‘, await getOtherData()) } } }) export default store
最好提前在你的 store 中初始化好所有所需属性。当需要在对象上添加新属性时,你应该使用 Vue.set(obj, ‘newProp‘, 123), 或者
以新对象替换老对象。例如,利用 stage-3 的对象展开运算符我们可以这样写:
state.obj = { ...state.obj, newProp: 123 }
组件a:
import { mapState, mapActions, mapMutations } from ‘vuex‘
export default {
    data() {
        return {}
    },    
    methods:{
        getTodoById(id) {
            return  this.$store.getters.getTodoById(id)
        },
        increment(payload)(){ //payload可以为对象,如:{ amount: 10}
            this.$store.commit(‘increment‘, payload)
            //对象风格的提交方式
            //this.$store.commit({type: ‘increment‘,amount: 10})
        },
        ...mapMutations([ 
            //mutation 都是同步事务,store.commit(‘increment‘), 任何由 "increment" 导致的状态变更都应该在此刻完成。
            //为解决异步问题我们引入action
            ‘increment‘, // 将 `this.increment()` 映射为 `this.$store.commit(‘increment‘)`
            //add: ‘increment‘ // 将 `this.add()` 映射为 `this.$store.commit(‘increment‘)`
            // `mapMutations` 也支持载荷:
            ‘incrementBy‘ // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit(‘incrementBy‘, amount)`
        ]),
        ...mapActions([
          ‘increment‘, // 将 `this.increment()` 映射为 `this.$store.dispatch(‘increment‘)`
          //add: ‘increment‘ // 将 `this.add()` 映射为 `this.$store.dispatch(‘increment‘)`
          // `mapActions` 也支持载荷:
          ‘incrementBy‘ // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch(‘incrementBy‘, amount)`
        ]),
        actionA() {
            store.dispatch(‘actionA‘).then(() => {
              // ...
            })
        }        
    },
    computed:{
        //count () {
        //  return this.$store.state.count
        //}         
        ...mapState({ // 使用对象展开运算符将此对象混入到外部对象中
            // 箭头函数可使代码更简练
            count: state => state.count,
            // 传字符串参数 ‘count‘ 等同于 `state => state.count`
            countAlias: ‘count‘,
            // 为了能够使用 `this` 获取局部状态,必须使用常规函数
            countPlusLocalState (state) {
              return state.count + this.localCount
            }
          }),
          
        doneTodosCount () {
            return this.$store.state.todos.filter(todo => todo.done).length
          },
        DoneTodos(){
            return this.$store.getters.doneTodos
        },
        getDoneTodosCount () {
            return this.$store.getters.doneTodosCount
        },
        // 使用对象展开运算符将 getter 混入 computed 对象中
        ...mapGetters([
          ‘doneTodosCount‘,
            //映射 `this.doneCount` 为 `store.getters.doneTodosCount`
            doneCount: ‘doneTodosCount‘
        ])        
    }    
}
main.js
import Vue from ‘vue‘ import store from ‘./store/‘ new Vue({ store }).$mount(‘#app‘)
使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式。这样可以使 linter 之类的工具发挥作用,同时把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然:
// mutation-types.js export const SOME_MUTATION = ‘SOME_MUTATION‘ // store.js import Vuex from ‘vuex‘ import { SOME_MUTATION } from ‘./mutation-types‘ const store = new Vuex.Store({ state: { ... }, mutations: { // 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名 [SOME_MUTATION] (state) { // mutate state } } })
Mutation 必须是同步函数
一条重要的原则就是要记住 mutation 必须是同步函数。为什么?请参考下面的例子:
mutations: { someMutation (state) { api.callAsyncMethod(() => { state.count++ }) } }
现在想象,我们正在 debug 一个 app 并且观察 devtool 中的 mutation 日志。每一条 mutation 被记录,devtools 都需要捕捉到前一状态和后一状态的快照。然而,在上面的例子中 mutation 中的异步函数中的回调让这不可能完成:因为当 mutation 触发的时候,回调函数还没有被调用,devtools 不知道什么时候回调函数实际上被调用——实质上任何在回调函数中进行的的状态的改变都是不可追踪的。
Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:
应用层级的状态应该集中到单个 store 对象中。
提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
异步逻辑都应该封装到 action 里面。
只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。
对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例:
├── index.html
├── main.js
├── api
│   └── ... # 抽取出API请求
├── components
│   ├── App.vue
│   └── ...
└── store
    ├── index.js          # 我们组装模块并导出 store 的地方
    ├── actions.js        # 根级别的 action
    ├── mutations.js      # 根级别的 mutation
    └── modules
        ├── cart.js       # 购物车模块
        └── products.js   # 产品模块
原文:http://www.cnblogs.com/fanlinqiang/p/8007317.html