Why do we need to use `.value` inside a template for a function that returns computed ref

169 Views Asked by At

I have a function that returns a ComputedRef like below

// a computed ref function
const publishedBooksMessage = () => computed(() => {
  return books.length > 0 ? 'Yes' : 'No'
})

To access the value returned from this function inside the template, I have to access the value property returned by that function like below. Working Fiddle

<span>{{ publishedBooksMessage().value === 'Yes' ? 'YES' : 'No' }}</span>

But, if this was a computed property like below

// a computed ref
const publishedBooksMessage = computed(() => {
  return books.length > 0 ? 'Yes' : 'No'
})

I could simply access it with the property variable itself without accessing the value property of that variable like below. Working Fiddle

<span>{{ publishedBooksMessage === 'Yes' ? 'YES' : 'No' }}</span>

The return type of the first and second implementation are ComputedRef. Then why does the first implementation needs to check the value property of the return value, where as with second one its sufficient to just check with the variable name itself?

2

There are 2 best solutions below

3
Boussadjra Brahim On BEST ANSWER

This principle of removing .value in template is called unwrapping, Based on official docs in the section Caveat when Unwrapping in Templates, they say :

Ref unwrapping in templates only applies if the ref is a top-level property in the template render context.

As this applies for nested ref properties it also applies on functions that return refs.

0
Nobsyde On

This is a limitation of ref unwrapping in the template - the reactive property needs to be exposed at the top level for it to be auto unwrapped.
Note that computed properties are computed refs, so they work exactly the same ".value" wise.
If you want to accomodate on the template this behaviour you have two solutions:

unref

wrap your code in unref(), like this:

<template>
// without unref, this wouldn't work
<span>{{ unref(publishedBooksMessage()) === 'Yes' ? 'YES' : 'No' }}    </span>
// without unref, this would work the same
<span>{{ unref(publishedBooksMessage) === 'Yes' ? 'YES' : 'No' }}    </span>
</template>

Use object destructuring and composables

instead of assigning publishedBooksMessage in an anonymous function, use object destructuring and composables like this:

<script setup>
function usePublishedBooksMessage() {
  const publishedBooksMessage = computed(() => {
    return books.length > 0 ? 'Yes' : 'No';
  });
  return {publishedBooksMessage}
}
const books = reactive([...])
const {publishedBooksMessage} = usePublishedBooksMessage()
</script>

<template>
  <span>{{ publishedBooksMessage === 'Yes' ? 'YES' : 'No' }}</span>
</template>