Si en tus proyectos Vue trabajas con la Composition API (algo que te
recomiendo), habrás utilizado reactive
para crear objetos reactivos. Por ejemplo, algo así:
const state = reactive({
online: true,
username: 'juanwmedia'
})
Ahora bien, ¿qué ocurre si quieres crear una referencia reactiva (con ref
) a una propiedad del objeto
reactivo state
?.
Quizás pienses que puedes acceder a él sin más y mantener la reactividad:
const username = ref(state.username) // ❌ no es reactivo
Sin embargo, esto no será reactivo, ya que lo estaremos enviando a ref
es un valor primitivo (en este caso
un string
), no la referencia al objeto reactivo que lo contiene.
toRef al rescate
Para poder crear una referencia reactiva a una propiedad de un objeto reactivo, Vue pone a nuestra
disposición toRef
. Utilizarlo es muy sencillo:
const username = toRef(state, 'username') // ✅ es reactivo
Como ves, toRef
acepta dos argumentos. El primero es el objeto reactivo donde vive la propiedad que queremos
referenciar. Por último, el identificador de la propiedad en sí.
Otro ejemplo típico donde es muy sencillo perder reactividad es trabajando con funciones compositoras, más conocidas como composables.
Supongamos que nuestro composable devuelve un objeto reactivo. Por ejemplo, las coordenadas del ratón:
export const useMouse = () => {
const coords = reactive({x: 0, y: 0});
function updateCoords({pageX, pageY}) {
console.log(pageX, pageY);
coords.x = pageX;
coords.y = pageY;
}
onMounted(() => window.addEventListener('mousemove', updateCoords));
onUnmounted(() => window.removeEventListener('mousemove', updateCoords));
return coords; // 👁 retornamos un objeto reactivo
};
Cuando ejecutemos el composable, es muy tentador desestructurar el objeto resultante:
const {x, y} = useMouse(); // ❌ perdemos la reactividad
Sin embargo, recuerda, no estamos trabajando con un objeto plano sino con un reactivo (con Proxy). No podemos extraer un valor sin más y mantener la reactividad.
toRefs
Para solucionar el problema tenemos otra función
llamada toRefs
, esta convierte un objeto reactivo en uno
plano, donde cada propiedad es una referencia reactiva (creada con toRef
) a la propiedad original del objeto
reactivo.
En nuestro ejemplo, podemos aplicar toRefs
en dos lugares. El primero es al hacer uso del composable.
const {x, y} = toRefs(useMouse()); // ✅ mantenemos la reactividad
O —más útil— retornar toRefs
desde el propio composable.
export const useMouse = () => {
...
return toRefs(coords);
};