.value in the Script

A ref is like a box with a value in it. In the script, you open the box with .value, both to read the value and to change it:

<script setup>
import { ref } from "vue";

const cups = ref(0);

function addCup() {
    cups.value++;
}
</script>

<template>
    <p>Cups today: {{ cups }}</p>
    <p>{{ cups > 2 ? "Maybe a tea next?" : "Enjoy your coffee!" }}</p>
    <button @click="addCup">One more coffee</button>
</template>

In the template, it's just cups, without .value, in {{ }} and in the condition alike. Vue unwraps refs in the template: it reads their .value for you. The template is where refs are used most, so this saves you writing .value again and again. The script is plain JavaScript, though, and there cups is the box, the ref itself.

And why const, when the number changes? Because cups is still the same box; only what's inside it changes. cups.value++ changes the inside, which const allows. What const doesn't allow is putting something else into cups itself, and you never want that anyway: Vue would lose track of it. So refs are always const.

Typical mistakes:

  • cups++ in the script, without .value. It tries to change the constant cups, so the console says TypeError: Assignment to constant variable., and the page stays as it was.
  • {{ cups.value }} in the template. Vue has already unwrapped the ref there, so cups is the number, and a number has no value. The page shows nothing in its place.
  • console.log(cups) prints the box, something like RefImpl { dep: Dep { … }, __v_isRef: true, … _value: 2 }. To see the number, print cups.value.

Instructions

  1. Write a function sellOne() that takes one croissant away, but only if there are any left: the number never goes below 0. Make it the click handler of Sell one.

  2. Write a function bakeMore() that adds 6 croissants, and make it the click handler of Bake more.

  3. Under the count, add a paragraph with the class status. When there are no croissants left, it says Sold out!, and otherwise Fresh from the oven. Use ? : in {{ }}.