Vue全家桶要点与事项手记之 Vuex

Vuex

Store对象的计算属性 getters

Store 对象的state可以理解为组件的data,而getter就可以理解为组件的computed

<div id="demo">
    {{ showStateDoneToDos }}
</div>

<script>

    const store = new Vuex.Store({
        state: {
            todos: [
                { id: 1, text: 'foo', done: true },
                { id: 2, text: 'bar', done: false },
                { id: 2, text: 'baz', done: true },
            ]
        },
        getters: {
            doneTodos: state => {
                return state.todos.filter(todo=> todo.done)
            }
        }
    });

    new Vue({
        el: "#demo",
        computed: {
            showStateDoneToDos: function() {
                return this.$store.getters.doneTodos;
            }
        },
        store: store
    });

</script>

若要通过带参数方法访问,则可以为计算属性构造闭包传递参数来实现效果


组件的计算属性辅助函数 mapState

mapState 是一个函数,返回的是一个对象,用于简化计算属性的编写

<div id="demo">
    {{ showStateDoneToDos }} <br/>
    {{ showStateDoneToDosAlias }} <br/>
    {{ reflectDoneToDos }}
</div>

<script>

    const store = new Vuex.Store({
        state: {
            todos: [
                { id: 1, text: 'foo', done: true },
                { id: 2, text: 'bar', done: false },
                { id: 2, text: 'baz', done: true },
            ]
        },
        getters: {
            doneTodos: state=> {
                return state.todos.filter(todo=> todo.done)
            }
        }
    });

    const doneTodos = "doneTodos";

    new Vue({
        el: "#demo",
        computed: {
            ...Vuex.mapGetters({
                reflectDoneToDos: doneTodos
            }),
            ...Vuex.mapState({
                showStateDoneToDos: (state, getters)=> {
                    return getters.doneTodos;
                }
            }),
            showStateDoneToDosAlias: function() {
                return this.$store.getters.doneTodos;
            }
        },
        store: store
    });

</script>

  • 这里...Vuex.mapState 是ES中对象展开运算符特性,因为 mapState 本身作为一个函数返回的是一个对象,这里运算符的效果是将mapState返回的对象的属性值展开,放到外面 computed 属性对应的值所在的对象中去
  • mapState函数的意义在于简化计算属性的编写(对比此例中 showStateDoneToDosAlias 的写法,但要注意箭头函数的作用域问题),mapState中的计算属性可以通过传入state和getters参数给箭头函数来进一步简写
  • 同样地,Vuex.mapGetters 是另一个辅助函数,用于将 store 中的getter映射到组件的计算属性中


Store对象状态更改 Mutation

<div id="demo">
    <p> {{ cnt }} </p>
    <button @click="increase({amount: 10})"> add payload to state </button>
    <button @click="decrease({amount: -10})"> sub payload to state </button>
</div>

<script>

    const store = new Vuex.Store({
        state: {
            cnt: 0
        },
        mutations: {
            increment: (state, payload)=> {
                state.cnt += payload.amount;
            }
        }
    });

    const increment = "increment";

    new Vue({
        el: "#demo",
        methods: {
            ...Vuex.mapMutations({
                increase: increment
            }),
            decrease: function(payload) {
                this.$store.commit(increment, payload);
            }
        },
        computed: Vuex.mapState({
            cnt: state=> state.cnt
        }),
        store: store
    });

</script>

提交 mutation 是更改 Vuex 的 store 中的状态的唯一方法

  • mutation 非常类似于事件,state 是第一个参数,payload 是第二个可选参数
  • 调用mutation的时候采用 vm.$store.commit(type[, payload]) 的形式提交
  • 同样地,在组件methods中可以使用 Vuex.mapMutations 来简写

  • Mutation 必须是同步函数


Mutation的异步化 Action

把上例中的Mutation使用Action异步化,使其延迟5秒执行

<div id="demo">
    <p> {{ cnt }} </p>
    <button @click="increaseAsync({amount: 10})"> add payload to state </button>
    <button @click="descreaseAsync({amount: -10})"> sub payload to state </button>
</div>

<script>

    const store = new Vuex.Store({
        state: {
            cnt: 0
        },
        mutations: {
            increment: (state, payload)=> {
                state.cnt += payload.amount;
            }
        },
        actions: {
            incrementAsync: (context, payload)=> {
                setTimeout(() => {
                    context.commit(increment, payload);
                }, 500);
            }
        }
    });

    const increment = "increment";
    const incrementAsync = "incrementAsync";

    new Vue({
        el: "#demo",
        methods: {
            ...Vuex.mapActions({
                increaseAsync: incrementAsync
            }),
            descreaseAsync: function(payload) {
                this.$store.dispatch(incrementAsync, payload);
            }
        },
        computed: Vuex.mapState({
            cnt: state=> state.cnt
        }),
        store: store
    });

</script>
  • 调用mutation的时候采用 vm.$store.dispatch (type[, payload]) 的形式分发
  • vm.$store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise
  • 同样地,在组件methods中可以使用 Vuex.mapActions 来简写
// promise示意
// ...

    actions: {
      actionA ({ commit }) {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            commit('someMutation')
            resolve()
          }, 1000)
        })
      },
      actionB ({ dispatch, commit }) {
        return dispatch('actionA').then(() => {
          commit('someOtherMutation')
        })
      }
    }

// ...

    store.dispatch('actionA').then(() => {
      // ...
    })


状态模块化 Module

<div id="demo">
    {{ nameA }} <br/>
    {{ nameB }} <br/>
    <button @click="changeName"> change name </button>
</div>

<script>

    const moduleA = {
        state: {
            name: "AAA"
        },
        mutations: {
            changeName: state=>
            state.name = "CCC"
        }
    };

    const moduleB = {
        state: {
            name: "BBB"
        },
        mutations: {
            changeName: state=>
            state.name = "CCC"
        }
    }

    const store = new Vuex.Store({
        modules: {
            a: moduleA,
            b: moduleB
        }
    });

    new Vue({
        el: "#demo",
        methods: Vuex.mapMutations(["changeName"]),
        computed: {
            nameA: function() {
                return this.$store.state.a.name
            },
            nameB: function() {
                return this.$store.state.b.name
            }
        },
        store: store
    });

</script>
  • 默认情况下,模块内部的 actions、mutations 和 getters 是注册在全局命名空间的,所以这个例子中两个重名的 mutations 会同时被调用

  • 局部的变量比如在moduleA这个例子里可以通过 this.$store.state.a.x 来访问



参考

Rest/Spread Properties for ECMAScript

-------------本文结束-------------