Reactive map not triggering Vue computed() function

Having a reactive relationship with an initially empty map: const map = reactive({});, I also have a computed property that checks if the map contains a key named "key":

const mapContainsKeyComputed = computed(() => map.hasOwnProperty("key"))
. However, the computed property does not update when the map is changed.

After struggling with this issue for a day, I was able to create a simple example to showcase 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 the map contain the key? {{mapContainsKeyComputed}}
  <br/>
  Watch: Does the map contain the key? {{mapContainsKeyWatched}}
  <br/>
  <button @click="map[key] = 'value'">Add Key-Value</button>
</template>

Despite going through numerous stackoverflow answers and Vue docs, the issue still persists.

  • Why doesn't the mapContainsKeyComputed property update?
  • If the reactive function doesn't track adding or removing keys in the map, why does Map: {{map}} (line 14) update seamlessly?
  • When I switch the map{} with an array[] and use "includes()" instead of "hasOwnProperty", it works perfectly. What's the difference?
  • How can I resolve this issue without resorting to the cumbersome "watch" solution where "map.hasOwnProperty(key)" needs to be duplicated?

EDIT: as pointed out by @estus-flask, this issue was a VueJS bug fixed in version 3.2.46. More information can be found here.

Answer №1

Reactivity in Vue needs explicit support for reactive object methods. Using hasOwnProperty is considered low-level and has not been supported for some time. This lack of support causes issues when trying to access map.hasOwnProperty(key) on a non-reactive raw object, as it does not trigger reactivity. As a result, the first computed call does not set a listener that can respond to changes in map.

One solution to this problem is to define key initially, which is a legacy approach that ensures reactivity works in both Vue 2 and 3:

const map = reactive({ key: undefined })

Another option is to check for the existence of the key property on the reactive object:

const mapContainsKeyComputed = computed(() => map[key] !== undefined)

A third approach is to utilize the in operator. Since Vue 3 uses Proxy for reactivity, property access can be detected using the has trap:

const mapContainsKeyComputed = computed(() => key in map)

The recent addition of support for hasOwnProperty in version 3.2.46 makes the code from the question compatible with the latest Vue version.

map may be misleading as it's not truly a map. If Map were utilized in Vue 3, calling map.has(key) would indeed trigger reactivity as intended.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Vue.js encountering an issue of receiving null for the JSON data upon the initial loading phase

Currently, I am expanding my knowledge on vue.js and experimenting with calling a json file to parse the data. Although everything seems to be functioning as intended, whenever I refresh the page, there is a momentary blank screen before the data loads. In ...

Tips on personalizing the FirebaseUI- Web theme

Can someone help me find a way to customize the logo and colors in this code snippet? I've only come across solutions for Android so far. if (process.browser) { const firebaseui = require('firebaseui') console.log(firebaseui) ...

Vue: function being called is not recognized within the inline-template component tag

I have a unique component that I am working with. It consists of various elements like modals, templates, and algolia search integration. <template> <div class="modal fade modal-primary" id="imageModal" tabindex="-1" role="dialog" aria-labelled ...

How to flip the value in v-model using VueJS

Below is the code snippet that I am working with: <input v-model="comb.inactive" type="checkbox" @click="setInactive(comb.id_base_product_combination)" > I am looking to apply the opposite value of comb.inactive to the v-model. Here are m ...

Learning how to handle URLEncoded format in Vue JS

Seeking guidance on how to handle URL Encoded format in postman to send data to my Vue JS app. Using the encoded format shown below, what npm package should I utilize for this task? https://i.stack.imgur.com/sBkXi.png ...

What is the best way to monitor changes in objects within a JavaScript array?

Currently, I am in the process of developing a Todo application using electron and Vue.js. In my project, there is an array of objects called items. Each object follows this format: {id: <Number>, item: <String>, complete: <Boolean>, ...

Top method for capturing a Vue JS and Quasar app in writing

I attempted to utilize the JSDoc for VueJS plugin according to the documentation but unfortunately, it didn't work out as expected https://github.com/Kocal/jsdoc-vuejs Can anyone recommend a reliable tool for documenting applications developed with ...

Seeking a method to display a tooltip exclusively when the element is cut off

Can someone assist me with finding a solution to display the tooltip element only when the span element is truncated? <q-td v-for="(col,index) in props.cols" :key="col.name" :props="props"> <span class="t ...

Why doesn't Vue's computed method call the 'get' function after setting a dependent value in the 'set' function

Allow me to explain how I define a computed value: Template : <date-picker v-model="rangeDate" type="date" format="jYYYY/jMM/jDD" display-format="jYYYY/jMM/jDD" input-c ...

Vuejs allows objects to trigger the execution of methods through elements

My goal is to utilize a function in order to individually set the content of table cells. In this specific scenario, I aim to enclose the status with the <strong> - Tag (I refrain from modifying the template directly because it is stored within a com ...

Guide on how to verify user identities with Azure AD in a Vue.js interface and backend developed with .Net 5

Our team is currently in the process of transitioning from .Net MVC to a Vue.js front-end. We had originally implemented a custom Attribute in our MVC version that utilized Azure AD for user authentication on specific pages. This attribute verified if user ...

Looking to cycle through arrays containing objects using Vue

Within my array list, each group contains different objects. My goal is to iterate through each group and verify if any object in a list meets a specific condition. Although I attempted to achieve this, my current code falls short of iterating through eve ...

Do not attempt to log after tests have finished. Could it be that you overlooked waiting for an asynchronous task in your test?

Currently, I am utilizing jest in conjunction with the Vue framework to create unit tests. My test example is successfully passing, however, I am encountering an issue with logging the request. How can I resolve this error? Is there a mistake in my usage o ...

The TypeScript rule in the project-specific .eslintrc.js file is not being applied as expected

Currently, I am following a tutorial on Ionic/Vue 3 which can be found here. However, when I try to serve the project, I encounter the following error: https://i.stack.imgur.com/k4juO.png It appears that my project-level .eslintrc.js file is not being ap ...

What is a better alternative to using the Event Bus for inter-component communication: data and computed properties

In the context of myComponent, there is a button that triggers the openOverlay function when clicked. This function emits an event called openedOverlay via EventBus. <button @click="openOverlay" </button> <Overlay /> methods: { openOver ...

Enhancing Your Vue Experience: A Guide to Highlighting and Selecting HTML Elements on Mouse Hover

Incorporating a navigation header using Vue, I utilize v-html to display it seamlessly. Check out the demo - here <section class="text-gray-700 font-heading font-medium relative bg-gray-50 bg-opacity-50"> <nav class="flex justify ...

sort response data based on date in vue

Is there a way to sort response data by date in vue2? Specifically, how can we filter the data by month, year, or week when a corresponding button is clicked? Here's an example of the response data I received: [ { "date": "2017-02-05", "views": 1, "r ...

Adding Typescript to a Nativescript-Vue project: A step-by-step guide

Struggling over the past couple of days to configure Typescript in a basic template-generated Nativescript-Vue project has been quite the challenge. Here's my journey: Initiated the project using this command: ERROR in Entry module not found: Erro ...

What causes the Vue.http configuration for vue-resource to be disregarded?

I am currently utilizing Vue.js 2.3.3, Vue Resource 1.3.3, and Vue Router 2.5.3 in my project while trying to configure Vue-Auth. Unfortunately, I keep encountering a console error message that reads auth.js?b7de:487 Error (@websanova/vue-auth): vue-resour ...

What is the best way to activate a modal in the parent component when a button is clicked in the child component?

Currently I have the following setup: panelHeader.vue (which is a child component) index.vue (the parent component where my main list view is) panelHeader.vue <template> <v-row> <div class="panelHeader"> ...