I have a reactivity around the initially empty map: const map =reactive({});
, and a calculation which tells If the map has a key "key": const mapContainsKeyCompulated = Computed(() => map.hasOwnProperty("key"))
. When I change the map, the calculations don't update.
I was stuck on this problem for a day and managed to come up with a minimal example that demonstrates the problem:
<script setup> import {computed, reactive, ref, watch} from "vue"; const map = reactive({}); const key = "key"; const mapContainsKeyComputed = computed(() => map.hasOwnProperty(key)) const mapContainsKeyWatched = ref(map.hasOwnProperty(key)); watch(map, () => mapContainsKeyWatched.value = map.hasOwnProperty(key)) </script> <template> Map: {{map}} <br/> Computed: does map contain "key"? {{mapContainsKeyComputed}} <br/> Watch: does map contain key? {{mapContainsKeyWatched}} <br/> <button @click="map[key] = 'value'">add key-value</button> </template>
I've read a bunch of stackoverflow answers and the Vue documentation but I still can't figure it out.
Map:{{map}}
(line 14) update fine? Edit: As @estus-flask mentioned, this is a VueJS bug fixed in 3.2.46.
Vue reactivity requires explicit support for reactive object methods.
hasOwnProperty
is quite low-level, so it has been unsupported for some time. Without support,map.hasOwnProperty(key)
will attempt to access thekey
on the non-reactive original object, and reactivity will not be triggered, so the firstcomputation The call does not set a listener that can be fired the next time
map
changes.One way to solve this problem is to first define the
key
(as suggested in another answer), which is the traditional way to make reactivity work in Vue 2 and 3:An alternative is to access the missing
key
property on the reactive object:Another way is to use the
in
operator. Since Vue 3 responds usingProxy
, it can detect that the property is accessed via thehas
trap:Support for
hasOwnProperty
has been recently added in 3.2.46, so the code in the question should work in the latest Vue version.map
is not a real map. This will be different in any Vue 3 version if usingMap
, Vue supports it and it is expected thatmap.has(key)
will trigger reactivity.