vuejs / vuex

🗃️ Centralized State Management for Vue.js.
https://vuex.vuejs.org
MIT License
28.42k stars 9.58k forks source link

Getters - Reactivity broken after registering new module #2197

Open lordolive opened 2 years ago

lordolive commented 2 years ago

Version

Vue: 3.2.45 Vuex: 4.1.0

Reproduction link

https://github.com/lordolive/vuex4-getters-reactivity

Steps to reproduce

Then in website :

What is expected?

The getter reactivity should still work and the count in the button should increment.

What is actually happening?

The getter accessed before the call to this.$store.registerModule() is no longer reactive, but the one that was not accessed before is still reactive

image

Additionnal comments

I first tried with MapGetters and had the same problem. Using $store.getters.count directly in the template solve the issue, but in my real application with multiple modules it is simply not pratical, especially considering that we are migrating a lot of code from Vue 2 which was working with mapGetters.

jkosir commented 2 years ago

Experiencing the same issue, the problem is the replacement and stopping of store._scope in resetStoreState which is called when registering a new module.

This stops currently active effectScope (store._scope) onto which all getters are bound and registers them again, which will cause any effect (computed, watch, e.g. count1 in reproduction example linked above) to become inactive and simply stop reacting to state changes.

A workaround (non-feasible, but still) is to subscribe to onScopeDispose of store._scope and re-register computed/watch effects you need, e.g. like this:

store._scope.run(() => {
    installWatcher()
})

function installWatcher () {
    onScopeDispose(() => {
        installWatcher()
    })
    watch(() => ...)
})

@kiaking @posva (since you originally added and reviewed this in https://github.com/vuejs/vuex/pull/1883) unless I'm missing something the replacement of store._scope shouldn't be needed (here)? If this is done then any effect referencing getters will become inactive and afaik there's no way to reactivate it from store.

EDIT: Ah I see the entire state is also replaced, therefore all computed-wrapped getters need to be reinitialized too. But any existing effect linked to a store getter will then stop working, as it will still be linked to previous (now inactive) computed-wrapped getter.

catalin-bratu commented 1 year ago

Any ETA till this bug will get fixed?

4refael commented 1 year ago

This is a serious regression.

136759790 commented 1 year ago

same problem

jaredplowman commented 1 year ago

We're in the same boat, we narrowed it down to this change in resetStoreState as well

Object.defineProperty(store.getters, key, {
   /*good->*/     get: () => computedObj[key](),
   /*bad->*/     // get: () => computedCache[key].value,
        enumerable: true // for local getters
      });

Interestingly enough any modules registered after the initial store still work without issue. We are rolling back to 4.0.2 for now.

ricardobuquet commented 1 year ago

Same problem here, this is really annoying

danielmiksavmlyr commented 1 year ago

Same problem for me - Vue 3.3.4 + Vuex 4.1.0. Thank you @jaredplowman for the tip with downgrading package. It solves this particular issue.

Super-Chama commented 1 year ago

Tracking the issue from https://github.com/vuejs/vuex/issues/2217 It's unsettling why such crucial issue is not fixed still. aside from rolling back to 4.0.2 other way to fix this will be using functional getters. since functional getters are not cached by default they seems to work fine.

renatodeleao commented 4 months ago

Just stumbled upon this. A coworker upgraded the package while I was doing a feature branch, had a mini panic attack when sync and a lot of things suddenly stopped working after visiting a very specific view — the one with dynamic modules.

Rollback to v4.0.2 fixes it.

I understand that vuex is "sunsetted" and we should move to pinia, but unfortunately I already spent the refactor budget migrating to vue@3.

Thanks OP et al 🙏

zangab commented 4 months ago

ANY updates?!?! this is actually a BIG issue.

beocaca commented 2 months ago

Recently, I have been migrating to vue@3, but it's breaking a lot of getters after registering new module. With a small refactor budget on a large project, my solution, unfortunately, has been to refactor everything in the getters. I don't use mapGetters anymore—it causes too many issues 🥲😭😓

export const getUserProfile = (state) => () => { return state.user; };

computed: getUserProfile() { return this.$store.getters["getUserProfile"](); },

weier910 commented 2 months ago

你的邮件我已收到!