Vue的状态管理vuex使用方法详解(8)

在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到

开发环境与发布环境

不要在发布环境下启用严格模式!严格模式会深度监测状态树来检测不合规的状态变更——请确保在发布环境下关闭严格模式,以避免性能损失。

类似于插件,可以让构建工具来处理这种情况:

const store = new Vuex.Store({ // ... strict: process.env.NODE_ENV !== 'production' })

表单处理

当在严格模式中使用 Vuex 时,在属于 Vuex 的 state 上使用 v-model 会比较棘手:

<input v-model="obj.message">

假设这里的 obj 是在计算属性中返回的一个属于 Vuex store 的对象,在用户输入时,v-model 会试图直接修改 obj.message。在严格模式中,由于这个修改不是在 mutation 函数中执行的, 这里会抛出一个错误。

用“Vuex 的思维”去解决这个问题的方法是:给 <input> 中绑定 value,然后侦听 input 或者 change 事件,在事件回调中调用 action:

<input :value="message" @input="updateMessage"> // ... computed: { ...mapState({ message: state => state.obj.message }) }, methods: { updateMessage (e) { this.$store.commit('updateMessage', e.target.value) } }

下面是 mutation 函数:

// ... mutations: { updateMessage (state, message) { state.obj.message = message } }

双向绑定的计算属性

必须承认,这样做比简单地使用“v-model + 局部状态”要啰嗦得多,并且也损失了一些 v-model 中很有用的特性。另一个方法是使用带有 setter 的双向绑定计算属性:

<input v-model="message"> // ... computed: { message: { get () { return this.$store.state.obj.message }, set (value) { this.$store.commit('updateMessage', value) } } }

测试 测试Mutation

Mutation 很容易被测试,因为它们仅仅是一些完全依赖参数的函数。这里有一个小技巧,如果在 store.js 文件中定义了 mutation,并且使用 ES2015 模块功能默认输出了 Vuex.Store 的实例,那么仍然可以给 mutation 取个变量名然后把它输出去:

const state = { ... } // `mutations` 作为命名输出对象 export const mutations = { ... } export default new Vuex.Store({ state, mutations })

下面是用 Mocha + Chai 测试一个 mutation 的例子

// mutations.js export const mutations = { increment: state => state.count++ } // mutations.spec.js import { expect } from 'chai' import { mutations } from './store' // 解构 `mutations` const { increment } = mutations describe('mutations', () => { it('INCREMENT', () => { // 模拟状态 const state = { count: 0 } // 应用 mutation increment(state) // 断言结果 expect(state.count).to.equal(1) }) })

测试Action

Action 应对起来略微棘手,因为它们可能需要调用外部的 API。当测试 action 的时候,需要增加一个 mocking 服务层——例如,可以把 API 调用抽象成服务,然后在测试文件中用 mock 服务回应 API 调用。为了便于解决 mock 依赖,可以用 webpack 和 inject-loader 打包测试文件。

下面是一个测试异步 action 的例子:

// actions.js import shop from '../api/shop' export const getAllProducts = ({ commit }) => { commit('REQUEST_PRODUCTS') shop.getProducts(products => { commit('RECEIVE_PRODUCTS', products) }) } // actions.spec.js // 使用 require 语法处理内联 loaders。 // inject-loader 返回一个允许我们注入 mock 依赖的模块工厂 import { expect } from 'chai' const actionsInjector = require('inject-loader!./actions') // 使用 mocks 创建模块 const actions = actionsInjector({ '../api/shop': { getProducts (cb) { setTimeout(() => { cb([ /* mocked response */ ]) }, 100) } } }) // 用指定的 mutaions 测试 action 的辅助函数 const testAction = (action, args, state, expectedMutations, done) => { let count = 0 // 模拟提交 const commit = (type, payload) => { const mutation = expectedMutations[count] try { expect(mutation.type).to.equal(type) if (payload) { expect(mutation.payload).to.deep.equal(payload) } } catch (error) { done(error) } count++ if (count >= expectedMutations.length) { done() } } // 用模拟的 store 和参数调用 action action({ commit, state }, ...args) // 检查是否没有 mutation 被 dispatch if (expectedMutations.length === 0) { expect(count).to.equal(0) done() } } describe('actions', () => { it('getAllProducts', done => { testAction(actions.getAllProducts, [], {}, [ { type: 'REQUEST_PRODUCTS' }, { type: 'RECEIVE_PRODUCTS', payload: { /* mocked response */ } } ], done) }) })

测试Getter

如果getter 包含很复杂的计算过程,很有必要测试它们。Getter 的测试与 mutation 一样直截了当。

测试一个 getter 的示例:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/f8f12dac30a05367ae20732c62aad03a.html