Skip to content

Commit f3abade

Browse files
committed
fix: add effect scope support
1 parent 31dbe7a commit f3abade

File tree

3 files changed

+36
-13
lines changed

3 files changed

+36
-13
lines changed

Diff for: src/store-util.js

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

44
export function genericSubscribe (fn, subs, options) {
@@ -29,30 +29,42 @@ export function resetStore (store, hot) {
2929

3030
export function resetStoreState (store, state, hot) {
3131
const oldState = store._state
32+
const oldScope = store._scope
3233

3334
// bind store public getters
3435
store.getters = {}
3536
// reset local getters cache
3637
store._makeLocalGettersCache = Object.create(null)
3738
const wrappedGetters = store._wrappedGetters
3839
const computedObj = {}
39-
forEachValue(wrappedGetters, (fn, key) => {
40-
// use computed to leverage its lazy-caching mechanism
41-
// direct inline function use will lead to closure preserving oldState.
42-
// using partial to return function with only arguments preserved in closure environment.
43-
computedObj[key] = partial(fn, store)
44-
Object.defineProperty(store.getters, key, {
45-
// TODO: use `computed` when it's possible. at the moment we can't due to
46-
// https://github.com/vuejs/vuex/pull/1883
47-
get: () => computedObj[key](),
48-
enumerable: true // for local getters
40+
const computedCache = {}
41+
42+
// create a new effect scope and create computed object inside it to avoid
43+
// getters (computed) getting destroyed on component unmount.
44+
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+
})
4957
})
5058
})
5159

5260
store._state = reactive({
5361
data: state
5462
})
5563

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+
5668
// enable strict mode for new state
5769
if (store.strict) {
5870
enableStrictMode(store)
@@ -67,6 +79,11 @@ export function resetStoreState (store, state, hot) {
6779
})
6880
}
6981
}
82+
83+
// dispose previously registered effect scope if there is one.
84+
if (oldScope) {
85+
oldScope.stop()
86+
}
7087
}
7188

7289
export function installModule (store, rootState, path, module, hot) {

Diff for: src/store.js

+6
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ export class Store {
3939
this._modulesNamespaceMap = Object.create(null)
4040
this._subscribers = []
4141
this._makeLocalGettersCache = Object.create(null)
42+
43+
// EffectScope instance. when registering new getters, we wrap them inside
44+
// EffectScope so that getters (computed) would not be destroyed on
45+
// component unmount.
46+
this._scope = null
47+
4248
this._devtools = devtools
4349

4450
// bind commit and dispatch to self

Diff for: test/unit/modules.spec.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ describe('Modules', () => {
126126
expect(mutationSpy).toHaveBeenCalled()
127127
})
128128

129-
it.only('should keep getters when component gets destroyed', async () => {
129+
it('should keep getters when component gets destroyed', async () => {
130130
const store = new Vuex.Store()
131131

132132
const moduleA = {
@@ -165,7 +165,7 @@ describe('Modules', () => {
165165
await nextTick()
166166

167167
store.commit('moduleA/increment')
168-
console.log(store.state.moduleA.value)
168+
169169
expect(store.getters['moduleA/getState']).toBe(2)
170170
})
171171
})

0 commit comments

Comments
 (0)