# Vue — Extra: Comparación con React
Semestre 01, 2026
## El panorama frontend
Hemos aprendido React a fondo.
React no es el único camino.
Vue es el principal competidor directo — misma categoría, filosofía distinta.
Conocer ambos hace mejores desarrolladores.
### Los tres grandes frameworks
| Framework | Creado por | Año | Modelo |
| --- | --- | --- | --- |
| React | Meta (Facebook) | 2013 | Biblioteca UI |
| Vue | Evan You | 2014 | Framework progresivo |
| Angular | Google | 2016 | Framework completo |
Esta presentación se enfoca en **Vue vs React** — los más similares en propósito.
### ¿Por qué aprender Vue si ya sé React?
* Vue domina en Asia y Europa Occidental — muchas empresas lo usan.
* Algunos proyectos existentes están en Vue — hay que poder leerlos.
* Vue tiene ideas propias que complementan el conocimiento de React.
* El mercado laboral premia conocer múltiples herramientas.
## Setup
### React (Vite)
```bash
npm create vite@latest mi-app -- --template react
cd mi-app
npm install
npm run dev
```
```
src/
├── App.jsx
├── main.jsx
└── components/
```
### Vue (Vite)
```bash
npm create vite@latest mi-app -- --template vue
cd mi-app
npm install
npm run dev
```
```
src/
├── App.vue
├── main.js
└── components/
```
La configuración inicial es prácticamente idéntica — ambos usan Vite.
La diferencia está en los archivos: `.jsx` vs `.vue`.
## Single File Components vs JSX
### React: todo en JavaScript
```jsx
// Tarjeta.jsx
import { useState } from 'react';
import './Tarjeta.css';
export function Tarjeta({ titulo, descripcion }) {
const [expandida, setExpandida] = useState(false);
return (
{titulo}
{expandida &&
{descripcion}
}
);
}
```
HTML, lógica y estilos en un solo archivo `.jsx` — todo es JavaScript.
### Vue: Single File Component
```vue
{{ titulo }}
{{ descripcion }}
```
Un `.vue` tiene tres secciones separadas: ``, `
```
En Vue: `ref(valor)` devuelve un objeto reactivo. Se accede con `.value` en el script, sin `.value` en el template.
### Estado con objetos
**React** — siempre crear un nuevo objeto:
```jsx
const [usuario, setUsuario] = useState({ nombre: '', email: '' });
// ✅ Crear copia con spread
setUsuario({ ...usuario, nombre: 'Ana' });
```
**Vue** — se puede mutar directamente:
```vue
```
`reactive` en Vue trackea los cambios internos del objeto automáticamente.
## Valores computados vs useMemo
### React: useMemo
```jsx
const productosFiltrados = useMemo(() =>
productos.filter(p => p.precio < filtro),
[productos, filtro]
);
```
### Vue: computed
```vue
```
Vue: `computed` se recalcula automáticamente cuando sus dependencias cambian.
No hay que declarar el array de dependencias — Vue lo detecta solo.
## Efectos secundarios
### React: useEffect
```jsx
useEffect(() => {
document.title = `Conteo: ${conteo}`;
}, [conteo]);
useEffect(() => {
const sub = suscribirse(id);
return () => sub.cancelar(); // cleanup
}, [id]);
```
### Vue: watch y watchEffect
```vue
```
`watch` — reaccionar a cambios de un valor específico (como `useEffect` con dependencias).
`watchEffect` — detecta dependencias automáticamente (como `useEffect` sin array).
## Props y comunicación
### Pasar datos hacia abajo
**React:**
```jsx
function Padre() {
return ;
}
function Hijo({ nombre, edad }) {
return
{nombre}, {edad} años
;
}
```
**Vue:**
```vue
{{ props.nombre }}, {{ props.edad }} años
```
`:edad="22"` — los dos puntos indican que el valor es JavaScript, no string.
Sin dos puntos: `edad="22"` sería el string `"22"`.
### Comunicación hacia arriba
**React** — callbacks como props:
```jsx
function Padre() {
function handleClick(valor) {
console.log('El hijo envió:', valor);
}
return ;
}
function Hijo({ onSeleccionar }) {
return ;
}
```
**Vue** — eventos con emit:
```vue
```
## Directivas de Vue vs JSX
Esta es la diferencia más visible. Vue usa directivas en el HTML, React usa JavaScript puro.
### Renderizado condicional
**React:**
```jsx
{activo && }
{activo ? : }
```
**Vue:**
```html
```
### Listas
**React:**
```jsx
{items.map(item => (
{item.nombre}
))}
```
**Vue:**
```html
{{ item.nombre }}
```
### Binding de atributos
**React:**
```jsx
setTexto(e.target.value)}
className="campo"
disabled={cargando}
/>
```
**Vue:**
```html
```
`v-model` es two-way binding — equivalente a `value` + `onChange` juntos en React.
### Eventos
**React:**
```jsx
console.log(e.key)} />
```
**Vue:**
```html
console.log(e.key)" />
```
`@click` es el shorthand de `v-on:click`.
### Tabla de equivalencias React → Vue
| React | Vue | Descripción |
| --- | --- | --- |
| `{condicion && }` | `v-if="condicion"` | Renderizado condicional |
| `{a ? : }` | `v-if` + `v-else` | Condicional con alternativa |
| `{items.map(...)}` | `v-for` | Listas |
| `className="clase"` | `class="clase"` | Clase CSS |
| `value` + `onChange` | `v-model` | Input controlado |
| `onClick` | `@click` | Evento de clic |
| `onChange` | `@change` | Evento de cambio |
| `{variable}` | `{{ variable }}` | Interpolación |
| `style={{ color: 'red' }}` | `:style="{ color: 'red' }"` | Estilos inline |
## Composables vs Custom Hooks
Ambos son la forma de reutilizar lógica entre componentes.
### React: Custom Hook
```jsx
// useFetch.js
import { useState, useEffect } from 'react';
export function useFetch(url) {
const [data, setData] = useState(null);
const [cargando, setCargando] = useState(true);
useEffect(() => {
fetch(url)
.then(r => r.json())
.then(data => { setData(data); setCargando(false); });
}, [url]);
return { data, cargando };
}
// Uso en un componente
const { data, cargando } = useFetch('/api/productos');
```
### Vue: Composable
```js
// useFetch.js
import { ref, watchEffect } from 'vue';
export function useFetch(url) {
const data = ref(null);
const cargando = ref(true);
watchEffect(async () => {
cargando.value = true;
const res = await fetch(url.value ?? url);
data.value = await res.json();
cargando.value = false;
});
return { data, cargando };
}
// Uso en un componente
const { data, cargando } = useFetch('/api/productos');
```
La convención de nombre es idéntica: `use` + nombre descriptivo.
## Estado global
### React: Context + Zustand
Context para estado simple, Zustand para apps medianas/grandes.
```jsx
// Con Zustand
import { create } from 'zustand';
const useCarritoStore = create(set => ({
items: [],
agregar: item => set(state => ({ items: [...state.items, item] })),
}));
// En cualquier componente
const { items, agregar } = useCarritoStore();
```
### Vue: Pinia (el estándar actual)
```js
// stores/carrito.js
import { defineStore } from 'pinia';
export const useCarritoStore = defineStore('carrito', {
state: () => ({ items: [] }),
actions: {
agregar(item) { this.items.push(item); }
},
});
// En cualquier componente
const carrito = useCarritoStore();
carrito.agregar(producto);
```
Pinia es al estado global de Vue lo que Zustand es al de React — ambos son la solución moderna y recomendada.
## Router
### React Router
```jsx
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
function App() {
return (
} />
} />
} />
);
}
```
### Vue Router
```js
// router/index.js
import { createRouter, createWebHistory } from 'vue-router';
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: Inicio },
{ path: '/productos', component: Productos },
{ path: '/productos/:id', component: Producto },
],
});
```
```vue
```
`` es el equivalente de `` con todos sus ``.
## Ciclo de vida
### React: todo con useEffect
```jsx
useEffect(() => { /* onMounted */ }, []);
useEffect(() => { return () => { /* onUnmounted */ }; }, []);
useEffect(() => { /* onUpdated */ }, [dependencia]);
```
### Vue: hooks de ciclo de vida explícitos
```vue
```
Vue tiene hooks específicos para cada momento — más explícito que `useEffect`.
## Comparación global
| Concepto | React | Vue |
| --- | --- | --- |
| Componente | `.jsx` con función | `.vue` con `` + `