Skip to content

Commit 704d43e

Browse files
authored
Merge pull request #1 from reedsy/reactivity-fix
Reactivity fix
2 parents 7b024d8 + 2095b01 commit 704d43e

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

src/store-util.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ export function resetStore (store, hot) {
3030
export function resetStoreState (store, state, hot) {
3131
const oldState = store._state
3232
const oldScope = store._scope
33+
const oldCache = store._computedCache
34+
const oldGettersKeySet = new Set(store.getters ? Object.keys(store.getters) : [])
3335

3436
// bind store public getters
3537
store.getters = {}
@@ -45,6 +47,10 @@ export function resetStoreState (store, state, hot) {
4547

4648
scope.run(() => {
4749
forEachValue(wrappedGetters, (fn, key) => {
50+
// Filter stale getters' key by comparing oldGetters and wrappedGetters,
51+
// the key does not be removed from oldGettersKeySet are the key of stale computed cache.
52+
// Stale computed cache: the computed cache should be removed as the corresponding module is removed.
53+
oldGettersKeySet.delete(key)
4854
// use computed to leverage its lazy-caching mechanism
4955
// direct inline function use will lead to closure preserving oldState.
5056
// using partial to return function with only arguments preserved in closure environment.
@@ -64,6 +70,7 @@ export function resetStoreState (store, state, hot) {
6470
// register the newly created effect scope to the store so that we can
6571
// dispose the effects when this method runs again in the future.
6672
store._scope = scope
73+
store._computedCache = computedCache
6774

6875
// enable strict mode for new state
6976
if (store.strict) {
@@ -82,6 +89,24 @@ export function resetStoreState (store, state, hot) {
8289

8390
// dispose previously registered effect scope if there is one.
8491
if (oldScope) {
92+
const deadEffects = []
93+
const staleComputedCache = new Set()
94+
oldGettersKeySet.forEach((staleKey) => {
95+
staleComputedCache.add(oldCache[staleKey])
96+
})
97+
oldScope.effects.forEach(effect => {
98+
// Use the staleComputedCache match the computed property of reactiveEffect,
99+
// to specify the stale cache
100+
if (effect.deps.length && !staleComputedCache.has(effect.computed)) {
101+
// Merge the effect that already have dependencies and prevent from being killed.
102+
scope.effects.push(effect)
103+
} else {
104+
// Collect the dead effects.
105+
deadEffects.push(effect)
106+
}
107+
})
108+
// Dispose the dead effects.
109+
oldScope.effects = deadEffects
85110
oldScope.stop()
86111
}
87112
}

test/unit/modules.spec.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { h, nextTick } from 'vue'
1+
import { computed, h, nextTick } from 'vue'
22
import { mount } from 'test/helpers'
33
import Vuex from '@/index'
44

@@ -925,4 +925,31 @@ describe('Modules', () => {
925925
/getters should be function but "getters\.test" in module "foo\.bar" is true/
926926
)
927927
})
928+
929+
it('module: computed getter should be reactive after module registration', () => {
930+
const store = new Vuex.Store({
931+
state: {
932+
foo: 0
933+
},
934+
getters: {
935+
getFoo: state => state.foo
936+
},
937+
mutations: {
938+
incrementFoo: state => state.foo++
939+
}
940+
})
941+
942+
const computedFoo = computed(() => store.getters.getFoo)
943+
store.commit('incrementFoo')
944+
expect(computedFoo.value).toBe(1)
945+
946+
store.registerModule('bar', {
947+
state: {
948+
bar: 0
949+
}
950+
})
951+
952+
store.commit('incrementFoo')
953+
expect(computedFoo.value).toBe(2)
954+
})
928955
})

0 commit comments

Comments
 (0)