Home > Software design >  Vue 3 refs behave differently if they are the property of an object
Vue 3 refs behave differently if they are the property of an object

Time:12-14

When using Vue 3's Composition API, I've noticed that inside a templte refs behave differently when they are accessed as the property of an object. I think this is best summarized by this example in the SFC Playground, but here's the key code (from a Single File Component):

    <script>
    import { ref } from 'vue';
    export default {
      setup() {
        const wut = ref(false);
        const obj = { wut };
        return {
          wut,
          obj,
        };
      },
    };
    </script>
    
    <template>
      <!-- obj.wut - false -->
      <h3>obj.wut - {{ obj.wut }}</h3>
      <!-- !!obj.wut - true -->
      <h3>!!obj.wut - {{ !!obj.wut }}</h3>
      <!-- obj.wut.value - false -->
      <h3>obj.wut.value - {{ obj.wut.value }}</h3>
      <!-- !!obj.wut.value - false -->
      <h3>!!obj.wut.value - {{ !!obj.wut.value }}</h3>
      <!-- does display -->
      <h3 v-if="obj.wut">display logic for this: v-if="obj.wut"</h3>
      <!-- does not display -->
      <h3 v-if="!obj.wut">display logic for this: v-if="!obj.wut"</h3>
      <!-- typeof obj.wut - object -->
      <h3>typeof obj.wut - {{ typeof obj.wut }}</h3>
    </template>

Can anybody explain why it appears to treat the ref as an object in some cases and interpret its value in other cases? Is this a bug, or by design?

CodePudding user response:

Short Answer: this is by design.

Long answer:

Please check Vue3 Guide -> Advanced Guides -> Reactivity -> Reactivity Fundamentals -> Ref unwrapping

Ref Unwrapping

When a ref is returned as a property on the render context (the object returned from setup()) and accessed in the template, it automatically shallow unwraps the inner value. Only the nested ref will require .value in the template:

In your example template, the obj.wut is a ref object, the wut is an unwrapped primitive value (a Boolean)

Extras:

  1. In your example, the obj.wut is rendered as false in the page, seems it is working without .value. That is because of a toDisplayString function in vue, it takes the ref object (obj.wut), it does JSON.stringify on the inner value of the ref object. If the value of wut is a string (const wut = ref('a string');), you will see extra double quotes around it in the rendered page, like "a string"
  2. There is also another tip in the doc, you can wrap the object in a reactive (const obj = reactive({ wut })) to access the unwrapped value in the template.
  • Related