浏览代码

throw if state is mutated outside mutation handlers

Evan You 9 年之前
父节点
当前提交
4c7e6f66fb
共有 2 个文件被更改,包括 42 次插入1 次删除
  1. 25 1
      src/index.js
  2. 17 0
      test/test.js

+ 25 - 1
src/index.js

@@ -17,16 +17,22 @@ export default class Vuex {
     state = {},
     actions = {},
     mutations = {},
-    middlewares = []
+    middlewares = [],
+    development = false
   } = {}) {
     // use a Vue instance to store the state tree
     this._vm = new Vue({
       data: state
     })
+    this._dispatching = false
     this.actions = Object.create(null)
     this._setupActions(actions)
     this._setupMutations(mutations)
     this._setupMiddlewares(middlewares, state)
+    // add extra warnings in debug mode
+    if (development) {
+      this._setupMutationCheck()
+    }
   }
 
   /**
@@ -51,6 +57,7 @@ export default class Vuex {
    */
 
   dispatch (type, ...payload) {
+    this._dispatching = true
     const mutation = this._mutations[type]
     const prevSnapshot = this._prevSnapshot
     const state = this.state
@@ -77,6 +84,7 @@ export default class Vuex {
     } else {
       console.warn(`[vuex] Unknown mutation: ${ type }`)
     }
+    this._dispatching = false
   }
 
   /**
@@ -96,6 +104,22 @@ export default class Vuex {
     }
   }
 
+  _setupMutationCheck () {
+    // a hack to get the watcher constructor from older versions of Vue
+    // mainly because the public $watch method does not allow sync
+    // watchers.
+    const unwatch = this._vm.$watch('__vuex__', a => a)
+    const Watcher = this._vm._watchers[0].constructor
+    unwatch()
+    new Watcher(this._vm, '$data', () => {
+      if (!this._dispatching) {
+        throw new Error(
+          '[vuex] Do not mutate vuex state outside mutation handlers.'
+        )
+      }
+    }, { deep: true, sync: true })
+  }
+
   _setupActions (actions, hot) {
     // keep the real action functions in an internal object,
     // and expose the public object which are just wrapper

+ 17 - 0
test/test.js

@@ -208,4 +208,21 @@ describe('Vuex', () => {
     expect(mutations[0].prevState.a).to.equal(1)
     expect(mutations[0].nextState.a).to.equal(3)
   })
+
+  it('development mode: warn mutations outside of handlers', function () {
+    const vuex = new Vuex({
+      state: {
+        a: 1
+      },
+      actions: {
+        test: () => (dispatch, state) => {
+          state.a++
+        }
+      },
+      development: true
+    })
+    expect(() => {
+      vuex.actions.test(2)
+    }).to.throw(/Do not mutate vuex state outside mutation handlers/)
+  })
 })