Tema
Qué es Vue y comparación con React
Antes de escribir código, conviene entender qué es Vue, qué problema resuelve y en qué se diferencia de React. Así podrás decidir con criterio qué herramienta usar en cada proyecto (y explicárselo a un cliente).
Concepto
El problema que resuelve
Con JavaScript puro, mantener la pantalla sincronizada con los datos se vuelve difícil: cada vez que algo cambia, tienes que buscar elementos con querySelector y actualizarlos a mano. En una app grande es fácil olvidar algún lugar y que la interfaz quede inconsistente.
Vue propone un modelo declarativo y reactivo:
- Declaras tus datos.
- Escribes una plantilla HTML que usa esos datos.
- Cuando los datos cambian, Vue actualiza automáticamente las partes de la página que dependen de ellos.
Analogía: es como una hoja de cálculo. Si la celda C1 es =A1+B1 y cambias A1, C1 se actualiza sola. En Vue, si cambias un dato, todo lo que lo usa en la pantalla se actualiza solo.
Un primer vistazo
Guarda esto como index.html y ábrelo en el navegador (es sólo para experimentar; en la siguiente lección crearás un proyecto real):
html
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Mi primer Vue</title>
</head>
<body>
<div id="app">
<h1>Hola, {{ nombre || 'mundo' }} 👋</h1>
<input v-model="nombre" placeholder="Escribe tu nombre">
<button @click="clics++">Clics: {{ clics }}</button>
<p v-if="clics >= 5">¡Ya van {{ clics }} clics!</p>
</div>
<script type="module">
import { createApp, ref } from 'https://unpkg.com/vue@3.5.13/dist/vue.esm-browser.js'
createApp({
setup() {
const nombre = ref('')
const clics = ref(0)
return { nombre, clics }
}
}).mount('#app')
</script>
</body>
</html>Escribe en el input y el saludo cambia al instante; haz clic y el contador sube. Nunca tocaste el DOM directamente.
Ideas clave de Vue
- Plantillas HTML: escribes HTML válido extendido con directivas (
v-if,v-for,v-model). Muy fácil para quien viene de HTML/CSS. - Reactividad automática: Vue rastrea qué datos usa cada parte de la plantilla y sólo actualiza lo necesario.
- Single File Components (
.vue): plantilla, lógica y estilos de un componente en un solo archivo. - Progresivo: puedes usar sólo la librería en una página o el ecosistema completo (Router, Pinia, Nuxt).
- Ecosistema oficial: Vue Router, Pinia, Vite (creado por el mismo autor de Vue) y Nuxt están coordinados con el núcleo.
Options API vs Composition API
Vue tiene dos estilos para escribir componentes. Verás ambos en proyectos existentes:
vue
<script setup>
import { ref, computed } from 'vue'
const precio = ref(100)
const cantidad = ref(2)
const total = computed(() => precio.value * cantidad.value)
function agregar() {
cantidad.value++
}
</script>
<template>
<p>{{ cantidad }} × ${{ precio }} = ${{ total }}</p>
<button @click="agregar">Agregar</button>
</template>vue
<script>
export default {
data() {
return { precio: 100, cantidad: 2 }
},
computed: {
total() {
return this.precio * this.cantidad
}
},
methods: {
agregar() {
this.cantidad++
}
}
}
</script>
<template>
<p>{{ cantidad }} × ${{ precio }} = ${{ total }}</p>
<button @click="agregar">Agregar</button>
</template>En este curso usamos Composition API con <script setup>: es más concisa, se lleva mejor con TypeScript y permite reutilizar lógica con composables. Si heredas un proyecto con Options API, los conceptos (datos reactivos, computadas, métodos) son los mismos.
Vue vs React
Ambos son excelentes y comparten ideas: componentes, estado reactivo, Virtual DOM, flujo de datos de padres a hijos. Las diferencias están en el estilo y la filosofía.
| Vue | React | |
|---|---|---|
| Tipo | Framework progresivo | Librería de UI |
| Plantillas | HTML con directivas (v-if, v-for) | JSX (JavaScript con sintaxis tipo HTML) |
| Reactividad | Automática: modificas el dato (contador.value++) | Explícita: llamas a setContador(...) e inmutabilidad |
| Renders | Vue sabe exactamente qué cambió | Vuelve a ejecutar el componente; optimizas con memo o el Compiler |
| Estilos | <style scoped> integrado | CSS Modules, Tailwind, CSS-in-JS (eliges tú) |
| Formularios | v-model (enlace bidireccional) | value + onChange |
| Rutas y estado | Oficiales: Vue Router, Pinia | De la comunidad: React Router, Zustand, TanStack |
| Meta-framework | Nuxt | Next.js |
| Curva de aprendizaje | Suave | Media |
| Mercado laboral | Grande (fuerte en Asia, Europa y agencias) | El más grande |
El mismo componente en ambos
vue
<script setup>
import { ref } from 'vue'
const tareas = ref(['Diseñar logo', 'Enviar cotización'])
const nueva = ref('')
function agregar() {
if (!nueva.value.trim()) return
tareas.value.push(nueva.value.trim()) // mutación directa: Vue lo detecta
nueva.value = ''
}
</script>
<template>
<input v-model="nueva" @keyup.enter="agregar" placeholder="Nueva tarea">
<ul>
<li v-for="t in tareas" :key="t">{{ t }}</li>
</ul>
<p v-if="tareas.length === 0">Sin tareas</p>
</template>jsx
import { useState } from 'react'
export default function Tareas() {
const [tareas, setTareas] = useState(['Diseñar logo', 'Enviar cotización'])
const [nueva, setNueva] = useState('')
function agregar() {
if (!nueva.trim()) return
setTareas([...tareas, nueva.trim()]) // copia nueva: inmutabilidad
setNueva('')
}
return (
<>
<input
value={nueva}
onChange={(e) => setNueva(e.target.value)}
onKeyUp={(e) => e.key === 'Enter' && agregar()}
placeholder="Nueva tarea"
/>
<ul>
{tareas.map((t) => <li key={t}>{t}</li>)}
</ul>
{tareas.length === 0 && <p>Sin tareas</p>}
</>
)
}¿Cuál elegir?
| Elige Vue si... | Elige React si... |
|---|---|
| Vienes de HTML/CSS y quieres resultados rápidos | Buscas el mercado laboral más amplio |
| Trabajas con Laravel o en una agencia que ya usa Vue | El equipo ya usa React o Next.js |
| Prefieres herramientas oficiales coordinadas | Quieres el ecosistema más grande de librerías |
| Necesitas agregar interactividad a páginas existentes | Planeas hacer apps móviles con React Native |
La buena noticia: los conceptos se transfieren. Si aprendes uno, el otro te costará la mitad.
Buena práctica
No elijas framework por moda: elige por el proyecto, el equipo y lo que el cliente podrá mantener. Para un cliente con un sitio en Laravel, Vue suele ser la opción más natural.
Error común
Usar el build de Vue desde un CDN (como en el ejemplo de arriba) para un proyecto real. Es útil para experimentar o para agregar algo pequeño a una página existente, pero para una app usa Vite: obtienes componentes .vue, recarga instantánea y un build optimizado.
Ejercicios
- Modifica el ejemplo HTML para agregar un botón "Reiniciar" que ponga el contador en 0 y que sólo aparezca cuando el contador sea mayor que 0.
- Agrega al ejemplo una lista de frutas (arreglo) que se muestre con
v-fory un input para agregar nuevas al presionar Enter.
Ver solución
html
<div id="app">
<h1>Hola, {{ nombre || 'mundo' }} 👋</h1>
<input v-model="nombre" placeholder="Escribe tu nombre">
<!-- 1 -->
<button @click="clics++">Clics: {{ clics }}</button>
<button v-if="clics > 0" @click="clics = 0">Reiniciar</button>
<!-- 2 -->
<input v-model="fruta" @keyup.enter="agregarFruta" placeholder="Nueva fruta">
<ul>
<li v-for="f in frutas" :key="f">{{ f }}</li>
</ul>
</div>
<script type="module">
import { createApp, ref } from 'https://unpkg.com/vue@3.5.13/dist/vue.esm-browser.js'
createApp({
setup() {
const nombre = ref('')
const clics = ref(0)
const fruta = ref('')
const frutas = ref(['Mango', 'Manzana'])
function agregarFruta() {
if (!fruta.value.trim()) return
frutas.value.push(fruta.value.trim())
fruta.value = ''
}
return { nombre, clics, fruta, frutas, agregarFruta }
}
}).mount('#app')
</script>Resumen
- Vue es un framework progresivo, declarativo y reactivo: cambias los datos y la pantalla se actualiza sola.
- Usa plantillas HTML con directivas y Single File Components (
.vue). - La Composition API con
<script setup>es el estilo moderno recomendado. - Frente a React: plantillas en vez de JSX, reactividad automática en vez de
setState, herramientas oficiales para rutas y estado.