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:
- In your example, the
obj.wut
is rendered asfalse
in the page, seems it is working without.value
. That is because of atoDisplayString
function in vue, it takes the ref object (obj.wut
), it doesJSON.stringify
on the inner value of the ref object. If the value ofwut
isa string
(const wut = ref('a string');
), you will see extra double quotes around it in the rendered page, like"a string"
- 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.