Las propiedades computadas en Vue.js son parecidas a las propiedades normales (o datos), pero con una diferencia importante: su valor depende de otras propiedades. Esto significa que si una de esas propiedades cambia, la propiedad computada se actualiza automáticamente. Son reactivas, así que no hace falta que tú las actualices manualmente, Vue lo hace por ti.
Ejemplo 1
Imagina que estás creando una pequeña calculadora para saber cuánto pagarás por un producto con IVA incluido. En lugar de hacer el cálculo manual o en una función cada vez que cambien los valores, puedes usar una propiedad computada que se actualice automáticamente cuando cambie el precio o el porcentaje del IVA.
Así Vue se encarga de todo por ti, y tú solo te enfocas en mostrar el resultado.
<template>
<h1>Calcular IVA(Impuesto al Valor Agregado)</h1>
<label>Precio(sin IVA)</label>
<input type="number" placeholder="precio" v-model="precio">
<br>
<label>Porcentaje del IVA(Ingresar numero entero)</label>
<input type="number" placeholder="Porcentaje IVA" v-model="porcentajeIva">
<br>
<p><strong>Precio con IVA:</strong> {{ precioConIva }}</p>
</template>
<script setup>
import { ref, computed } from 'vue';
// Se define la propiedad `precio` como reactiva usando ref().
const precio = ref(0);
//Se define la propiedad `porcentajeIva` como reactiva usando ref().
const porcentajeIva = ref(0);
// La propiedad `precioConIva` es computed y recalcula su valor automáticamente
const precioConIva = computed(() => {
//Se calcula el impuesto multiplicando el precio por la division del `porcentajeIva` entre 100 para obtener el valor en decimal
const impuesto = precio.value*(porcentajeIva.value/100);
//El resultado del precio con el IVA incluido
const resultado = precio.value+impuesto;
return resultado; // Redondea a 2 decimales
});
</script>
Ejemplo 2
Supongamos que queremos calcular el promedio de tres notas: tareas, laboratorio y examen. Lo lógico sería sumar las tres y dividir entre 3, pero queremos que este promedio se actualice automáticamente cada vez que cambiemos alguna nota. Para eso, usamos una propiedad computada en Vue.js.
<template>
<h1>Calcular Promedio</h1>
<label>Tareas:</label>
<input type="number" placeholder="Tareas" v-model="tareas">
<br>
<label>Laboratorio:</label>
<input type="number" placeholder="Laboratorio" v-model="laboratorio">
<br>
<label>Examen:</label>
<input type="number" placeholder="Examen" v-model="examen">
<br>
<p><strong>Promedio:</strong> {{ promedio }}</p>
</template>
<script setup>
import { ref, computed } from 'vue';
// Se definen las propiedades `tareas`,`laboratorio`,`examen` reactivas usando ref()
const tareas = ref(0);
const laboratorio = ref(0);
const examen = ref(0);
// La propiedad `promedio` es computed y recalcula su valor automáticamente
const promedio = computed(() => {
const resultado = (tareas.value + laboratorio.value + examen.value) / 3;
return resultado.toFixed(2); // Redondea a 2 decimales
});
</script>
Propiedades computadas vs métodos
las propiedades computadas y los métodos se escriben de diferente manera pero ellos funcionan de diferente manera.
Métodos:
Se ejecutan cuando son llamados, normalmente a través de un evento (como un clic o una acción del usuario). Esto significa que el cálculo o cambio de valor se hace de manera manual, ya que depende de que algo lo active.
<template>
<h1>Calcular Promedio con Método</h1>
<label>Tareas:</label>
<input type="number" placeholder="Tareas" v-model="tareas">
<br>
<label>Laboratorio:</label>
<input type="number" placeholder="Laboratorio" v-model="laboratorio">
<br>
<label>Examen:</label>
<input type="number" placeholder="Examen" v-model="examen">
<br>
<button @click="calcularPromedio">Calcular Promedio</button>
<p><strong>Promedio:</strong> {{ promedio }}</p>
</template>
<script setup>
import { ref } from 'vue';
const tareas = ref(0);
const laboratorio = ref(0);
const examen = ref(0);
const promedio = ref(0);
const calcularPromedio = () => {
const resultado = (tareas.value + laboratorio.value + examen.value) / 3;
promedio.value = resultado.toFixed(2);
};
</script>
En el ejemplo anterior, para obtener el promedio final, es necesario presionar el botón ‘Calcular Promedio’. Si no se ejecuta el método calcularPromedio()
, no habrá ningún resultado. El promedio no se genera de forma automática, sino que requiere una acción del usuario para actualizarse.
Propiedades Computadas:
Por otro lado, las propiedades computadas son dinámicas: se actualizan automáticamente cada vez que cambia alguna de las propiedades de las que dependen.
Tomemos como ejemplo el cálculo del promedio: si cambiamos el valor de tareas
, laboratorio
o examen
, el promedio se actualiza solo, sin necesidad de hacer clic en nada o llamar a una función. Vue se encarga de todo.
getters y setters en propiedades computadas
Normalmente, cuando usamos propiedades computadas en Vue, solo escribimos una función que devuelve un valor. Eso sería el getter. Pero también se puede agregar un setter, que nos permite actualizar datos cuando esa propiedad cambia.
En pocas palabras:
El getter sirve para mostrar un valor.
El setter sirve para cambiar otros valores cuando modificamos ese valor computado.
Ejemplo
Imagínate que tienes el nombre y el apellido por separado, pero quieres mostrar el nombre completo y, además, poder cambiarlo desde un solo campo.
Con un get
y un set
, puedes hacer eso fácilmente: mostrar el nombre completo, y también actualizar el nombre y el apellido si alguien escribe un nuevo nombre completo.
<template>
<h1>App</h1>
</template>
<script setup>
import { ref, computed } from 'vue'
// Se definen dos propiedades reactivas usando ref()
const nombre = ref('Jose')
const apellido = ref('Ramirez')
// La propiedad `nombreCompleto` es un computed con getter y setter
const nombreCompleto = computed({
get() {
// El getter nos permite obtener el valor de la propiedad,
// en este caso, la concatenación de `nombre` y `apellido`
return nombre.value + ' ' + apellido.value
},
set(nuevoNombre) {
// Usamos la desestructuración de arrays para dividir `nuevoNombre`
// y asignarlo a `nombre` y `apellido`
[nombre.value, apellido.value] = nuevoNombre.split(' ')
}
})
// Mostramos el nombre completo usando los valores iniciales
console.log(nombreCompleto.value) // "Jose Ramirez"
// Se asigna un nuevo nombre completo
nombreCompleto.value = 'Maria Garcia'
// Se imprime el nuevo nombre completo después del cambio
console.log(nombreCompleto.value) // "Maria Garcia"
</script>
Conclusión
Las propiedades computadas con getters y setters nos permiten manejar de manera sencilla valores derivados y a la vez tener control sobre cómo modificarlos. Son una herramienta poderosa cuando necesitamos que los datos se sincronicen automáticamente sin tener que escribir lógica adicional. Además, facilitan la interacción con los usuarios, permitiendo actualizar y mostrar información sin perder la claridad y simplicidad en el código.
La reactividad en Vue.js es el mecanismo que permite que los datos y la interfaz de usuario se mantengan sincronizados automáticamente. Esto significa que cuando un valor cambia, todas las partes de la aplicación que dependen de él se actualizan sin necesidad de intervención manual.
En JavaScript puro, no hay una manera sencilla de detectar cambios en una variable a menos que se programe una función para monitorizar. Sin embargo, Vue.js nos facilita esto con ref()
y reactive()
.
Declarando variables reactivas con ref()
Vue.js nos proporciona la función ref()
para hacer que una variable simple (como un número, cadena o booleano) sea reactiva.
Ejemplo usando ref()
<template>
<h1>App</h1>
<input type="text" v-model="mensaje">
<p>{{mensaje}}</p>
</template>
<script setup>
import {ref} from 'vue';
const mensaje = ref('Aqui aparece el mensaje');
</script>
Explicacion
Enlazamos la variable mensaje usando v-model,esto nos permite que el valor que contenga el input sera el valor de la variable mensaje
<input type="text" v-model="mensaje">
en esta linea declaramos la variable mensaje y gracias a ref() es reactiva,
const mensaje = ref('Aqui aparece el mensaje');
Al ingresar texto en el input el valor de el mensaje cambia automáticamente,sin la necesidad de hacerlo manualmente a esto se le llama reactividad
.
Ejemplo usando computed()
computed también es un tipo de reactividad,se usan para definir propiedades calculadas que dependen de otras propiedades reactivas,estas se actualizan automáticamente cuando los valores de las propiedades de las que dependen cambian por ejemplo
<template>
<h1>App</h1>
<input type="number" v-model="numero1">
<input type="number" v-model="numero2">
<p>Numero 1 => {{numero1}}</p>
<p>Numero 2 => {{numero2}}</p>
<p>Resultado => {{resultado}}</p>
</template>
<script setup>
import {ref,computed} from 'vue';
const numero1 = ref(0);
const numero2= ref(0);
const resultado = computed(()=>numero1.value+numero2.value);
</script>
al declarar la variable resultado como computed()
esta es reactiva y cambiara su valor cada vez que cambie el valor de numero1 o numero2,computed()
memoriza el resultado y solo se vuelve a calcular cuando cambian sus dependencias.
const resultado = computed(()=>numero1.value+numero2.value);
uso de .value
como se puede observar, al calcular
el resultado accedemos al valor de cada propiedad reactiva de la que este depende utilizando.value
, esto se debe a que cuando declaramos numero1 y numero2 como ref()
, vue.js
crea un objeto con una sola propiedad,en este caso value
, esta propiedad value
es la que almacena el valor interna de la variable reactiva,por lo tanto para acceder o modificar el valor,se necesita usar .value
.
Ejemplo usando watch()
watch()
observa una variable reactiva y este ejecuta una función cuando su valor cambie,
<template>
<h1>App</h1>
<button @click="incrementarContador">Incrementar Contador</button>
<p>contador => {{contador}}</p>
</template>
<script setup>
import {ref,watch} from 'vue';
const contador = ref(0);
watch(contador,(nuevoValor,anteriorValor)=>{
console.log(`el valor del contador cambio de ${anteriorValor} a ${nuevoValor}`);
});
const incrementarContador = ()=>{
contador.value++;
};
</script>
Explicación
- Se define contador como una variable reactiva:
const contador = ref(0);
- Se usa
watch(contador, (nuevoValor, anteriorValor) => {...})
para ejecutar una acción cada vez que contador cambie.
- Dentro de
watch()
, nuevoValor almacena el valor actualizado y anteriorValor almacena el valor anterior. Estos valores solo existen dentro de watch().
Cada vez que se hace clic en el botón, el contador cambia y watch()
se ejecuta.
Ejemplo 2 de watch()
<template>
<h1>App</h1>
<p>contador => {{contador}}</p>
</template>
<script setup>
import {ref,watch} from 'vue';
let contador = ref(0);
watch(contador,(nuevoValor,anteriorValor)=>{
console.log(`El valor del contador cambio de ${anteriorValor} a ${nuevoValor}`);
});
setInterval(() => {
contador.value++;
if(contador.value >= 10){
contador.value=0;
}
}, 1000);
</script>
Explicacion
con la función setInterval() se incrementa el valor del contador cada segundo y cuando el contador es igual o mayor que 10,se reinicia a 0,watch() registra los cambios en la consola.
watchEffect()
¿que es watchEffect()?
es similar a watch()
,pero con la diferencia que no necesita especificar que variable reactiva quieres observar,se ejecuta inmediatamente y rastrea cualquier valor reactivo dentro de su función,entonces cada vez que una variable que hayamos declarado como reactiva dentro de su función este se ejecutara.
Ejemplo usando watchEffect()
<template>
<h1>App</h1>
<button @click="incrementar">Incrementar Contador</button>
<p>Contador: {{contador}}</p>
</template>
<script setup>
import { ref, watchEffect } from 'vue';
const contador = ref(0);
watchEffect(() => {
console.log(`El contador cambió de valor a: ${contador.value}`);
});
const incrementar = () => {
contador.value++;
};
</script>
Explicación
iniciamos la variable contador
const contador = ref(0);
con las siguientes lineas, rastreamos el valor que ah cambiado sin especificarlo en el watch
y cada vez que el valor del contador incremente,por ende este cambie disparar el watchEffect()
y mostrara en consola un mensaje,describiendo el cambio.
watchEffect(() => {
console.log(`El contador cambió de valor a: ${contador.value}`);
});
con la funcion incrementar()
incrementamos el valor del contador de a 1
const incrementar = () => {
contador.value++;
};
Ejemplo con mas de una variable reactiva
<template>
<h1>App</h1>
<button @click="incrementar">Incrementar Contador</button>
<p>Contador: {{contador}}</p>
</template>
<script setup>
import { ref, watchEffect } from 'vue';
const contador = ref(0);
const contador2 = ref(0);
watchEffect(() => {
console.log(`los contadores cambiaron su valor a: contador 1 ${contador.value} y contador 2 ${contador2.value}`);
});
const incrementar = () => {
contador.value++;
contador2.value=contador2.value+2;
};
</script>
No es mas que una modificación del anterior ejemplo,se crea un segundo contador que incrementa de a 2 y al igual que con el primer contador al cambiar de valor se ejecuta el watchEffect() automáticamente al cambiar los valores.
¿Cuándo usar watchEffect()
?
- Cuando quieres ejecutar código cada vez que cambie alguna dependencia sin declararlas manualmente.
- Para operaciones como sincronizar datos, llamadas a APIs o manipular elementos del DOM.
- Cuando necesitas que la función se ejecute inmediatamente al montarse el componente.
reactive()
reactive()
es una función de Vue 3 que permite crear objetos reactivos. Es decir, convierte un objeto y todas sus propiedades en reactivas, de modo que cualquier cambio en ellas será detectado automáticamente por Vue. A diferencia de ref()
, que se usa para valores únicos como números o cadenas, reactive()
se usa cuando necesitamos manejar objetos completos con múltiples propiedades.
Ejemplo
<template>
<h1>App</h1>
<button @click="cambiarDatos">Cambiar persona</button>
<p>Nombre: {{persona.nombre}}</p>
<p>Edad: {{persona.edad}}</p>
</template>
<script setup>
import {reactive } from 'vue';
const persona = reactive({
nombre:'jose',
edad:30,
});
const cambiarDatos = () => {
persona.nombre = 'dan';
persona.edad = 25;
console.log(`Nuevo nombre: ${persona.nombre}, Nueva edad: ${persona.edad}`);
};
</script>
Explicación
se crea un objeto,el objeto persona con dos propiedades nombre y edad que ya con sus valores
const persona = reactive({
nombre:'jose',
edad:30,
});
con la funcion cambiardatos(),modificamos los valores del nombre y la edad
const cambiarDatos = () => {
persona.nombre = 'dan';
persona.edad = 25;
console.log(`Nuevo nombre: ${persona.nombre}, Nueva edad: ${persona.edad}`);
};
Conclusión
Vue.js simplifica la reactividad con ref()
, computed()
, watch()
y reactive(), permitiendo que los datos y la interfaz de usuario se mantengan sincronizados automáticamente. Mientras que ref()
convierte variables en reactivas, computed()
permite crear valores derivados de manera eficiente, y watch()
nos ayuda a reaccionar a cambios en los datos.