Skip to content

Commit 125c229

Browse files
committed
fix: avoid resetting store state when registering a dynamic module
Fixes #2197 At the moment, when registering a dynamic module, we call `resetStoreState()` just to register the getters for the new module. It seems unnecessary to reset the entire store state in this case, and this actually also leads to [other issues][1]. This change is based on the test case added in #2201 The approach taken in this change is to refactor the getter registration into its own function, and call that new method when registering a dynamic module instead of resetting the store state. [1]: #2197
1 parent 99d0b99 commit 125c229

File tree

2 files changed

+36
-26
lines changed

2 files changed

+36
-26
lines changed

src/store-util.js

+25-22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { reactive, computed, watch, effectScope } from 'vue'
2-
import { forEachValue, isObject, isPromise, assert, partial } from './util'
2+
import { isObject, isPromise, assert, partial } from './util'
33

44
export function genericSubscribe (fn, subs, options) {
55
if (subs.indexOf(fn) < 0) {
@@ -35,36 +35,19 @@ export function resetStoreState (store, state, hot) {
3535
store.getters = {}
3636
// reset local getters cache
3737
store._makeLocalGettersCache = Object.create(null)
38-
const wrappedGetters = store._wrappedGetters
39-
const computedObj = {}
40-
const computedCache = {}
4138

4239
// create a new effect scope and create computed object inside it to avoid
4340
// getters (computed) getting destroyed on component unmount.
4441
const scope = effectScope(true)
45-
46-
scope.run(() => {
47-
forEachValue(wrappedGetters, (fn, key) => {
48-
// use computed to leverage its lazy-caching mechanism
49-
// direct inline function use will lead to closure preserving oldState.
50-
// using partial to return function with only arguments preserved in closure environment.
51-
computedObj[key] = partial(fn, store)
52-
computedCache[key] = computed(() => computedObj[key]())
53-
Object.defineProperty(store.getters, key, {
54-
get: () => computedCache[key].value,
55-
enumerable: true // for local getters
56-
})
57-
})
58-
})
42+
// register the newly created effect scope to the store so that we can
43+
// dispose the effects when this method runs again in the future.
44+
store._scope = scope
45+
registerGetters(store, Object.keys(store._wrappedGetters))
5946

6047
store._state = reactive({
6148
data: state
6249
})
6350

64-
// register the newly created effect scope to the store so that we can
65-
// dispose the effects when this method runs again in the future.
66-
store._scope = scope
67-
6851
// enable strict mode for new state
6952
if (store.strict) {
7053
enableStrictMode(store)
@@ -86,6 +69,26 @@ export function resetStoreState (store, state, hot) {
8669
}
8770
}
8871

72+
export function registerGetters (store, getterKeys) {
73+
const computedObj = {}
74+
const computedCache = {}
75+
76+
store._scope.run(() => {
77+
getterKeys.forEach((key) => {
78+
const fn = store._wrappedGetters[key]
79+
// use computed to leverage its lazy-caching mechanism
80+
// direct inline function use will lead to closure preserving oldState.
81+
// using partial to return function with only arguments preserved in closure environment.
82+
computedObj[key] = partial(fn, store)
83+
computedCache[key] = computed(() => computedObj[key]())
84+
Object.defineProperty(store.getters, key, {
85+
get: () => computedCache[key].value,
86+
enumerable: true // for local getters
87+
})
88+
})
89+
})
90+
}
91+
8992
export function installModule (store, rootState, path, module, hot) {
9093
const isRoot = !path.length
9194
const namespace = store._modules.getNamespace(path)

src/store.js

+11-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import {
99
installModule,
1010
resetStore,
1111
resetStoreState,
12-
unifyObjectStyle
12+
unifyObjectStyle,
13+
registerGetters
1314
} from './store-util'
1415

1516
export function createStore (options) {
@@ -227,9 +228,15 @@ export class Store {
227228
}
228229

229230
this._modules.register(path, rawModule)
230-
installModule(this, this.state, path, this._modules.get(path), options.preserveState)
231-
// reset store to update getters...
232-
resetStoreState(this, this.state)
231+
const module = this._modules.get(path)
232+
const namespace = this._modules.getNamespace(path)
233+
installModule(this, this.state, path, module, options.preserveState)
234+
235+
const getterKeys = []
236+
module.forEachGetter((getter, key) => {
237+
getterKeys.push(namespace + key)
238+
})
239+
registerGetters(this, getterKeys)
233240
}
234241

235242
unregisterModule (path) {

0 commit comments

Comments
 (0)