Explorar o código

Implemented getters into the store.

Passing the stores state to the getters.
The getters get combined.
Blake Newman %!s(int64=9) %!d(string=hai) anos
pai
achega
d3ddc02a6f
Modificáronse 3 ficheiros con 91 adicións e 10 borrados
  1. 36 9
      src/index.js
  2. 16 0
      src/util.js
  3. 39 1
      test/test.js

+ 36 - 9
src/index.js

@@ -1,4 +1,4 @@
-import { createAction, mergeObjects, deepClone } from './util'
+import { createAction, validateHotModules, mergeObjects, deepClone } from './util'
 import devtoolMiddleware from './middlewares/devtool'
 import createLogger from './middlewares/logger'
 
@@ -20,6 +20,7 @@ export class Store {
     actions = {},
     mutations = {},
     middlewares = [],
+    getters = {},
     strict = false
   } = {}) {
     // bind dispatch to self
@@ -33,9 +34,11 @@ export class Store {
     })
     this._dispatching = false
     this.actions = Object.create(null)
+    this.getters = Object.create(null)
     this._setupActions(actions)
     this._setupMutations(mutations)
     this._setupMiddlewares(middlewares, state)
+    this._setupGetters(getters)
     // add extra warnings in strict mode
     if (strict) {
       this._setupMutationCheck()
@@ -104,13 +107,16 @@ export class Store {
    *        - {Object} [mutations]
    */
 
-  hotUpdate ({ actions, mutations } = {}) {
+  hotUpdate ({ actions, mutations, getters } = {}) {
     if (actions) {
       this._setupActions(actions, true)
     }
     if (mutations) {
       this._setupMutations(mutations)
     }
+    if (getters) {
+      this._setupGetters(getters, true)
+    }
   }
 
   /**
@@ -163,13 +169,34 @@ export class Store {
     })
     // delete public actions that are no longer present
     // after a hot reload
-    if (hot) {
-      Object.keys(this.actions).forEach(name => {
-        if (!actions[name]) {
-          delete this.actions[name]
-        }
-      })
-    }
+    if (hot) validateHotModules(this.actions, actions)
+  }
+
+  /**
+   * Set up the callable getter functions exposed to components.
+   * This method can be called multiple times for hot updates.
+   * We keep the real getter functions in an internal object,
+   * and expose the public object which are just wrapper
+   * functions that point to the real ones. This is so that
+   * the reals ones can be hot reloaded.
+   *
+   * @param {Object} getters
+   * @param {Boolean} [hot]
+   */
+  _setupGetters (getters, hot) {
+    this._getters = Object.create(null)
+    getters = Array.isArray(getters)
+      ? mergeObjects(getters)
+      : getters
+    Object.keys(getters).forEach(name => {
+      this._getters[name] = (...payload) => getters[name](this.state, ...payload)
+      if (!this.getters[name]) {
+        this.getters[name] = (...args) => this._getters[name](...args)
+      }
+    })
+    // delete public getters that are no longer present
+    // after a hot reload
+    if (hot) validateHotModules(this.getters, getters)
   }
 
   /**

+ 16 - 0
src/util.js

@@ -16,6 +16,22 @@ export function createAction (action, store) {
   }
 }
 
+/**
+ * Validates hot api - unassigns any methods
+ * that do not exist.
+ *
+ * @param {Object} currentMethods
+ * @param {Object} newMethods
+ */
+
+export function validateHotModules (currentMethods, newMethods) {
+  Object.keys(currentMethods).forEach(name => {
+    if (!newMethods[name]) {
+      delete currentMethods[name]
+    }
+  })
+}
+
 /**
  * Merge an array of objects into one.
  *

+ 39 - 1
test/test.js

@@ -31,6 +31,11 @@ describe('Vuex', () => {
       actions: {
         test: TEST
       },
+      getters: {
+        getA (state) {
+          return state.a
+        }
+      },
       mutations: {
         [TEST] (state, n) {
           state.a += n
@@ -39,6 +44,7 @@ describe('Vuex', () => {
     })
     store.actions.test(2)
     expect(store.state.a).to.equal(3)
+    expect(store.getters.getA()).to.equal(3)
   })
 
   it('async action', function (done) {
@@ -92,12 +98,31 @@ describe('Vuex', () => {
             state.c += n
           }
         }
+      ],
+      getters: [
+        {
+          getA (state) {
+            return state.a
+          }
+        },
+        {
+          getB (state) {
+            return state.b
+          },
+
+          getC (state) {
+            return state.c
+          }
+        }
       ]
     })
     store.actions.test(2)
     expect(store.state.a).to.equal(3)
     expect(store.state.b).to.equal(3)
     expect(store.state.c).to.equal(1)
+    expect(store.getters.getA()).to.equal(3)
+    expect(store.getters.getB()).to.equal(3)
+    expect(store.getters.getC()).to.equal(1)
     store.actions.test2(2)
     expect(store.state.c).to.equal(3)
   })
@@ -105,7 +130,8 @@ describe('Vuex', () => {
   it('hot reload', function () {
     const store = new Vuex.Store({
       state: {
-        a: 1
+        a: 1,
+        b: 2
       },
       actions: {
         test: TEST
@@ -114,11 +140,17 @@ describe('Vuex', () => {
         [TEST] (state, n) {
           state.a += n
         }
+      },
+      getters: {
+        getA (state) {
+          return state.b
+        }
       }
     })
     const test = store.actions.test
     test(2)
     expect(store.state.a).to.equal(3)
+    expect(store.getters.getA()).to.equal(2)
     store.hotUpdate({
       actions: {
         test: ({ dispatch }, n) => dispatch(TEST, n + 1)
@@ -127,10 +159,16 @@ describe('Vuex', () => {
         [TEST] (state, n) {
           state.a = n
         }
+      },
+      getters: {
+        getA (state) {
+          return state.a
+        }
       }
     })
     test(999)
     expect(store.state.a).to.equal(1000)
+    expect(store.getters.getA()).to.equal(1000)
   })
 
   it('middleware', function () {