diff --git a/src/store-util.js b/src/store-util.js index e3ba18609..5cbe9aa2f 100644 --- a/src/store-util.js +++ b/src/store-util.js @@ -1,5 +1,5 @@ import { reactive, computed, watch, effectScope } from 'vue' -import { forEachValue, isObject, isPromise, assert, partial } from './util' +import { isObject, isPromise, assert, partial } from './util' export function genericSubscribe (fn, subs, options) { if (subs.indexOf(fn) < 0) { @@ -35,36 +35,19 @@ export function resetStoreState (store, state, hot) { store.getters = {} // reset local getters cache store._makeLocalGettersCache = Object.create(null) - const wrappedGetters = store._wrappedGetters - const computedObj = {} - const computedCache = {} // create a new effect scope and create computed object inside it to avoid // getters (computed) getting destroyed on component unmount. const scope = effectScope(true) - - scope.run(() => { - forEachValue(wrappedGetters, (fn, key) => { - // use computed to leverage its lazy-caching mechanism - // direct inline function use will lead to closure preserving oldState. - // using partial to return function with only arguments preserved in closure environment. - computedObj[key] = partial(fn, store) - computedCache[key] = computed(() => computedObj[key]()) - Object.defineProperty(store.getters, key, { - get: () => computedCache[key].value, - enumerable: true // for local getters - }) - }) - }) + // register the newly created effect scope to the store so that we can + // dispose the effects when this method runs again in the future. + store._scope = scope + registerGetters(store, Object.keys(store._wrappedGetters)) store._state = reactive({ data: state }) - // register the newly created effect scope to the store so that we can - // dispose the effects when this method runs again in the future. - store._scope = scope - // enable strict mode for new state if (store.strict) { enableStrictMode(store) @@ -86,6 +69,26 @@ export function resetStoreState (store, state, hot) { } } +export function registerGetters (store, getterKeys) { + const computedObj = {} + const computedCache = {} + + store._scope.run(() => { + getterKeys.forEach((key) => { + const fn = store._wrappedGetters[key] + // use computed to leverage its lazy-caching mechanism + // direct inline function use will lead to closure preserving oldState. + // using partial to return function with only arguments preserved in closure environment. + computedObj[key] = partial(fn, store) + computedCache[key] = computed(() => computedObj[key]()) + Object.defineProperty(store.getters, key, { + get: () => computedCache[key].value, + enumerable: true // for local getters + }) + }) + }) +} + export function installModule (store, rootState, path, module, hot) { const isRoot = !path.length const namespace = store._modules.getNamespace(path) diff --git a/src/store.js b/src/store.js index e22c74b5d..6fa83d576 100644 --- a/src/store.js +++ b/src/store.js @@ -9,7 +9,8 @@ import { installModule, resetStore, resetStoreState, - unifyObjectStyle + unifyObjectStyle, + registerGetters } from './store-util' export function createStore (options) { @@ -228,8 +229,10 @@ export class Store { this._modules.register(path, rawModule) installModule(this, this.state, path, this._modules.get(path), options.preserveState) - // reset store to update getters... - resetStoreState(this, this.state) + + const namespace = this._modules.getNamespace(path) + const getterKeys = Object.keys(rawModule.getters || {}).map((key) => namespace + key) + registerGetters(this, getterKeys) } unregisterModule (path) {