Convert Between ref and reactive Properties
toRef, toRefs & unref
These helpers preserve reactivity when destructuring or passing pieces of a reactive object — and let composables accept either a ref or a plain value.
What you'll learn
- Use toRef to make a single ref from a reactive property
- Use toRefs to destructure without losing reactivity
- Use unref to read a possibly-ref value
Reactive objects lose reactivity when you destructure or pass a property by value. The trio toRef, toRefs, and unref lets you bridge between the two reactive worlds.
toRef — One Property at a Time
toRef(state, 'key') returns a ref that stays in sync with state.key.
import { reactive, toRef } from 'vue'
const state = reactive({ name: 'Ada', age: 36 })
const nameRef = toRef(state, 'name')
console.log(nameRef.value) // 'Ada'
state.name = 'Bob'
console.log(nameRef.value) // 'Bob' toRefs — Destructure Everything
toRefs(state) returns an object whose properties are all refs.
import { reactive, toRefs } from 'vue'
const state = reactive({ count: 0, name: 'Ada' })
const { count, name } = toRefs(state)
count.value++ // updates state.count
console.log(state) // { count: 1, name: 'Ada' } This is the standard pattern when a composable returns a reactive object.
function useUser() {
const state = reactive({ user: null, loading: false })
return toRefs(state)
}
// Caller can destructure freely
const { user, loading } = useUser() unref — Read Either
unref(x) returns x.value if x is a ref, otherwise x. Use it when accepting either form.
import { unref, ref } from 'vue'
function log(input: number | { value: number }) {
console.log(unref(input))
}
log(5) // 5
log(ref(5)) // 5 For reactive tracking, prefer toValue — it accepts refs, getters, or plain values.
import { toValue, type MaybeRefOrGetter } from 'vue'
function double(x: MaybeRefOrGetter<number>) {
return toValue(x) * 2
}
double(3) // 6
double(ref(3)) // 6
double(() => count.value) // 6 — getter form This pattern is how modern composables (VueUse, etc.) accept “ref or value” inputs gracefully.
Conditional Rendering — v-if →