Brett Fisher
Brett Fisher

Reputation: 612

Vue Composition API - Can't add a property to an object

I'm using Vue's Composition API. When I write some code that adds a property to a ref object, the template renderer does not seem to detect the change. Here is my code:

<template>
  <div id="app">
    <button @click="updateObj">Click</button>
    <div v-if="obj[1]">{{ obj[1] }}</div>
  </div>
</template>

<script>
import { defineComponent, ref } from "@vue/composition-api";

export default defineComponent({
  name: "App",
  setup() {
    const obj = ref({});

    const updateObj = () => {
      obj.value[1] = "hello";
      console.log(obj.value);
    };

    return {
      obj,
      updateObj,
    };
  },
});
</script>

Clicking on the button calls updateObj which then sets the property "1" on obj to "hello". If obj[1] is set, you should see "hello" in the browser, but nothing is displayed. Here's a codepen to the demo.

I've been using the Composition API for months now and feel like I've gotten the hang of it, but I have no idea what's going on here. I've also tried reactive instead of ref but still no luck.

Upvotes: 2

Views: 3306

Answers (2)

Trevor Geise
Trevor Geise

Reputation: 121

I'm adding my answer here so when I google this again in six months I'll find it.

If you are using composition api with Vue 2, you need to use set to add a new tracked property to an object.

From https://github.com/vuejs/composition-api

⚠️ set and del workaround for adding and deleting reactive properties ⚠️ Warning: set and del do NOT exist in Vue 3. We provide them as a workaround here, due to the limitation of Vue 2.x reactivity system.

In Vue 2, you will need to call set to track new keys on an object(similar to Vue.set but for reactive objects created by the Composition API). In Vue 3, you can just assign them like normal objects.

Similarly, in Vue 2 you will need to call del to ensure a key deletion triggers view updates in reactive objects (similar to Vue.delete but for reactive objects created by the Composition API). In Vue 3 you can just delete them by calling delete foo.bar.

<template>
  <div id="app">
    <button @click="updateObj">Click</button>
    <div v-if="obj[1]">{{ obj[1] }}</div>
  </div>
</template>

<script>
import { defineComponent, ref, set } from "@vue/composition-api";

export default defineComponent({
  name: "App",
  setup() {
    const obj = ref({});

    const updateObj = () => {
      set(obj.value, 1, "hello");
      console.log(obj.value);
    };

    return {
      obj,
      updateObj,
    };
  },
});
</script>

LIVE DEMO

Upvotes: 2

Boussadjra Brahim
Boussadjra Brahim

Reputation: 1

You should use ref when you work with primitive values, if you want to use an object you have to use reactive, in the official docs they say :

If using ref, we are largely translating style (1) to a more verbose equivalent using refs (in order to make the primitive values reactive).

  • Using reactive is nearly identical to style (2). We only need to create the object with reactive and that's it.
  • Using reactive is nearly identical to style (2). We only need to create the object with reactive and that's it.

...
Use ref and reactive just like how you'd declare primitive type variables and object variables in normal JavaScript. It is recommended to use a type system with IDE support when using this style.

To make it reactive assign the object directly to the ref's value :

 obj.value = { 1: "hello" };

LIVE DEMO

Upvotes: 2

Related Questions