Two ways to make something reactive, one of which requires .value everywhere in script and neither of which requires it in a template.
const count = ref(0);
count.value++; // .value in script
// {{ count }} // unwrapped in the template
const state = reactive({ count: 0 });
state.count++; // no .value
// and the trap: destructuring loses reactivity
const { count } = state; // a plain number now
const { count } = toRefs(state); // a ref, still reactive
The rule that works is ref for a single value and reactive for an object you will not destructure — and since composables return objects that callers destructure, most of them use ref and toRefs. The automatic unwrapping in templates is convenient and is the reason the distinction is invisible until it bites. A ref holding an object is deeply reactive too, which surprises people expecting it to be shallow.