vuejs / vuex

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

state 'hasOwnProperty' getter reactivity #1981

Closed mrichar1 closed 3 years ago

mrichar1 commented 3 years ago

Version

4.0.0

Reproduction link

https://codesandbox.io/s/vue-3-vuex-4-test-forked-926e7?file=/src/store/index.js

Steps to reproduce

The minimal reproduction starts with an empty state, then fetches data from an api (with a delay). To reproduce, just run the app with the if test using hasOwnProperty.

What is expected?

The computed property should react to the state update whe the API returns.

What is actually happening?

When hasOwnProperty is used, the computed property never reacts when the state updates. However when in is used it works as expected.


hasOwnProperty was working on Vue2/Vuex3, but no longer works on Vue3/Vuex4. I'm happy to be told that hasOwnProperty is the 'wrong way' to check state but given it's a commonly used method on objects I thought it worth flagging up this unusual behaviour.

cuebit commented 3 years ago

Parameterized getters can only derive things that are based in state. Since x doesn't exist, the immediate returning value is final therefore Vue has no dependencies to track. Iteration, such as for in, will enumerate members thus promoting dependency tracking.

The following may give you more hope in future:

hasOwnProperty was working on Vue2/Vuex3

At least not with the example you've provided it doesn't. The outcome is exactly the same in Vue 2/Vuex 3.

mrichar1 commented 3 years ago

So I went back to see why my existing Vue2 project works, and it appears to be that in Vue2 I am using Vue.set in the mutations (in my 'real' project state is more deeply nested).

I have forked the sandbox and switched to Vue2/Vue.set to demonstrate this:

https://codesandbox.io/s/vue-2-vuex-3-test-0jcve?file=/src/store/index.js

Thanks to your comment I now appreciate why the Vue3 example doesn't work as something needs to trigger dependency tracking.

I'm not sure if this change in behaviour is enough to count as a bug/reopen the issue, but I thought it worth flagging up.

cuebit commented 3 years ago

@mrichar1 the change in behaviour is on Vue's part, not Vuex. If anything, Vue.set was required due to Vue 2's reactivity limitations. Computed properties still behave in the same fashion in that they will trigger tracking updates should they have a dependency to track. This also still applies to method returning computations, since no caching is taking place but instead the method is invoked with the changed value. So it's important to realise that whatever the situation is, computed properties require visibility to dependencies. However, as previously mentioned, hasOwnProperty makes it impossible for Vue to reach the dependency initially when it returns false.

Hope this helps.