From n00b to ZeroCool / Profesionalización
React: el imperio que se rehúsa a caer (y por qué tu equipo regresa)
React domina por DX, ecosistema y pragmatismo. Cuándo elegirlo, cómo montarlo con Vite+TS y evitar traps que rompen el deploy.
Lo que vale la pena leer aquí
Son las 11:47 pm. Ya traes la laptop medio vieja con el ventilador sonando como helicóptero y te cae el mensaje del backend: “Ya quedó el endpoint”. Abres el repo del frontend y… ahí está otra vez: React.
Son las 11:47 pm. Ya traes la laptop medio vieja con el ventilador sonando como helicóptero y te cae el mensaje del backend: “Ya quedó el endpoint”. Abres el repo del frontend y… ahí está otra vez: React.
La semana pasada alguien en el standup juró que “React ya murió” y que ahora sí nos íbamos a casar con el framework de moda. Pero llega el bug en production, el nuevo dev entra al equipo, el cliente pide un cambio “bien rápido” antes del deadline… y el stack termina regresando a lo conocido.
React no es perfecto. Pero en el jale real —con prisa, deuda técnica y PRs que se mezclan— suele ser la opción que te deja entregar sin apostar tu chamba a una tendencia.
Qué te vas a llevar
- Por qué React sigue vigente (sin fanboyismo) y qué piezas lo sostienen.
- Cómo decidir React vs otra opción con criterios de negocio y equipo.
- Un setup moderno con Vite + React + TypeScript que aguanta crecimiento.
- Un patrón práctico para data fetching + estado sin hacer sopa de hooks.
- Errores comunes que siguen costando horas (y cómo salir del hoyo).
Por qué el imperio no se cae (la parte nada glamorosa)
React no manda porque sea “el más elegante”. Manda porque es predecible en medio del caos:
- Hiring y onboarding: siempre hay alguien que ya lo tocó. Aunque sea “medio lo usó”, eso baja el costo de arranque, sobre todo cuando el presupuesto viene apretado.
- Ecosistema: routing, forms, tablas, charts, UI kits, testing, SSR/SSG, monorepos… hay herramientas buenas y, cuando no están tan buenas, al menos hay opciones.
- Modelo mental estable: componentes + props + hooks. Cambian librerías alrededor, pero el core se mantiene.
- Pragmatismo: sirve igual para el dashboard interno que nadie presume (pero paga la renta) que para un e-commerce con SSR.
La comparación que más duele pero más ayuda: React es como el “Java del frontend”. A veces te desespera, pero cuando hay que operar a escala, hay tooling, hay docs, y hay banda que sabe cómo sacar un rollback sin incendiar todo.
La decisión real: ¿React para qué sí y para qué no?
Úsalo cuando:
- El producto va para largo y necesitas mantenibilidad.
- Hay rotación de gente (freelancers, practicantes, nuevos hires).
- Necesitas SSR/SEO (p. ej. Next.js) o una app grande con mucho estado.
- Quieres bajar el riesgo de apostar por algo que quizá no exista en 18 meses.
Piénsalo dos veces cuando:
- Es un micrositio/landing y el deadline es “mañana a las 9 am”. A veces Astro/SSG o hasta HTML+Tailwind gana por KO.
- Es muy pequeño y no quieres el costo mental del ecosistema.
- Tu equipo odia React y ya es sólido en otra opción (migrar por moda sale carísimo).
React moderno que no duele (Vite + TS + bases sanas)
Asumamos algo real: no estás haciendo un “hello world”. Estás iniciando algo que va a recibir features, bugs, PRs y algún deploy nocturno.
1) Crea el proyecto con Vite + React + TypeScript
npm create vite@latest mi-app -- --template react-ts
cd mi-app
npm install
npm run dev
¿Por qué Vite? Porque el setup es rápido, el dev server vuela y te quita talacha de configuración. En equipos chicos/medianos, esa fricción menos se nota un buen.
2) Estructura mínima de carpetas (para no acabar con /components2 y /components-final)
Una estructura que he visto sobrevivir producción:
src/
app/
routes/
App.tsx
features/
auth/
users/
shared/
ui/
lib/
hooks/
types/
main.tsx
- features/: módulos por dominio (auth, users, billing). Aquí vive la lógica de negocio.
- shared/ui: componentes reusables (Button, Modal). Ojo: no metas “UserTable” aquí.
- shared/lib: helpers (formatMoney, api client, validators).
Decisión práctica: si todavía no tienes dominios clarísimos, empieza con 2–3 features y deja que el producto te vaya diciendo cómo se parte. Lo que mata proyectos no es “no tener la arquitectura perfecta”; es el refactor eterno por no poner límites.
3) Lint + format desde el día 1 (sí, aunque sea MVP)
Porque el día que entra alguien nuevo, el repo se vuelve tianguis si no hay reglas.
npm i -D eslint prettier eslint-config-prettier eslint-plugin-react-hooks
.eslintrc.cjs (simple y útil):
module.exports = {
env: { browser: true, es2021: true },
extends: [
'eslint:recommended',
'plugin:react-hooks/recommended',
'prettier'
],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
rules: {
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }]
}
}
.prettierrc:
{
"singleQuote": true,
"semi": true
}
Decisión práctica: si el equipo no tiene tiempo para pelear tabs vs spaces, dejen que el tooling lo decida. La energía guárdenla para lo que sí rompe production.
4) Data fetching y caching: deja de vivir en useEffect + setState
El clásico: cada pantalla tiene su useEffect que hace fetch, maneja loading, error, reintentos, cache… y luego te explota un bug rarísimo cuando cambias de route o le dan refresh.
Solución realista: TanStack Query (React Query).
npm i @tanstack/react-query
Setup en main.tsx:
import React from 'react';
import ReactDOM from 'react-dom/client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import App from './app/App';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 1,
refetchOnWindowFocus: false
}
}
});
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</React.StrictMode>
);
Ejemplo de feature:
// src/features/users/api.ts
export type User = { id: string; name: string };
export async function fetchUsers(): Promise<User[]> {
const res = await fetch('/api/users');
if (!res.ok) throw new Error('Error cargando users');
return res.json();
}
// src/features/users/useUsers.ts
import { useQuery } from '@tanstack/react-query';
import { fetchUsers } from './api';
export function useUsers() {
return useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
staleTime: 30_000
});
}
// src/features/users/UsersPage.tsx
import { useUsers } from './useUsers';
export function UsersPage() {
const { data, isLoading, error } = useUsers();
if (isLoading) return <p>Cargando…</p>;
if (error) return <p>Se cayó esto: {(error as Error).message}</p>;
return (
<ul>
{data!.map((u) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
);
}
Decisión práctica: React Query te compra estabilidad. Menos bugs de “se quedó loading”, menos duplicación, mejor UX con cache. Y sí: en el coworking con WiFi chafa o en el camión compartiendo hotspot, esa resiliencia se siente.
5) Estado global: no metas Redux “por si acaso”
Regla de supervivencia:
- Server state (lo que viene de API): React Query.
- UI state local (modal abierto, input value):
useState. - App state compartido (tema, sesión, permisos, filtros globales): Context bien hecho o Zustand.
Ejemplo mini con Zustand (cuando de verdad lo necesitas):
npm i zustand
// src/shared/lib/useSession.ts
import { create } from 'zustand';
type SessionState = {
token: string | null;
setToken: (t: string | null) => void;
};
export const useSession = create<SessionState>((set) => ({
token: null,
setToken: (token) => set({ token })
}));
Tradeoff honesto: Context funciona, pero si metes medio mundo en un provider te ganas re-renders y esa sensación de “lento raro”. Zustand suele ser más directo cuando crece el proyecto.

Screenshots sugeridos
- Estructura de carpetas en VS Code (src/app, src/features, src/shared).
- React Query Devtools mostrando cache y estados (loading/success/error).
- Network tab: llamada a
/api/userscon respuesta y tiempos. - Lighthouse/Performance antes y después de quitar re-renders innecesarios.
Errores comunes (los que sí rompen releases) + cómo evitar el hoyo
1) useEffect con dependencias mal puestas (o sin dependencias)
Síntoma: requests duplicados, loops infinitos, UI que “parpadea”.
Salida:
- Para data fetching: usa React Query.
- Para effects reales: revisa dependencias y evita derivar estado de props “porque sí”.
Mal:
useEffect(() => {
fetch('/api/users').then(...);
});
Mejor (si no usas React Query):
useEffect(() => {
fetch('/api/users').then(...);
}, []);
2) Keys chafas en listas
Síntoma: inputs que cambian solos, elementos que se reordenan raro.
Salida: usa IDs estables. No uses el index.
{users.map((u) => (
<Row key={u.id} user={u} />
))}
3) “Optimizar” con useMemo y useCallback por fe
Síntoma: código más enredado, deps que nadie entiende, cero mejora real.
Salida: primero mide (React DevTools Profiler). Memoiza cuando:
- pasas callbacks a listas grandes
- componentes pesados re-renderizan por props nuevas
4) Mezclar server state y UI state en el mismo objeto
Síntoma: actualizas un checkbox y “mágicamente” cambias el cache; luego haces refetch y se pierde.
Salida:
- Server state se queda en Query.
- Lo editable se queda local (o en un form library) y al guardar haces mutation.
5) Router + fetch manual = pantallas inconsistentes
Síntoma: navegas rápido, llegan respuestas tarde y pisan estado. El bug aparece justo cuando el jefe pide “un cambio en corto” y tú ya estabas por cerrar.
Salida: React Query maneja consistencia y cancelación mejor (y si te pones estricto, sumas AbortController). Si estás en Next.js, aprovecha los patrones de data fetching del framework.

Checklist final (para que React no se vuelva telenovela)
- Proyecto con Vite + React + TS corriendo y con scripts claros.
- ESLint + Prettier instalados y corriendo en pre-commit (ideal) o CI (mínimo).
- Estructura por dominios (
features/) en lugar de “componentes por todo el mundo”. - Server state con React Query (queries y mutations), no
useEffectpor pantalla. - Estado global solo si duele; si lo necesitas, elige una opción y estandariza.
- Listas con keys estables, nada de index.
- Re-renders medidos antes de meter
useMemopor costumbre.
FAQ
1) ¿React sigue valiendo la pena en 2026?
Sí, si tu prioridad es shipping + mantenibilidad + hiring. No es el único camino, pero sigue siendo una apuesta de riesgo bajo comparado con stacks que cambian “la forma correcta” cada seis meses.
2) ¿Vite o Next.js para empezar?
- Vite: SPA, dashboards internos, herramientas internas, apps sin SEO fuerte.
- Next.js: cuando necesitas SSR/SSG, rutas file-based, metadata/SEO, o un enfoque más full-stack.
3) ¿Necesito Redux?
La mayoría no. Server state con React Query y UI con useState/Context. Redux entra cuando hay flujos complejos, mucha colaboración, o necesitas tooling de debugging específico (y aun así, evalúa Zustand).
4) ¿Cómo manejo forms sin sufrir?
Si el form es simple, useState y listo. Si hay validación, campos dinámicos y errores: React Hook Form + Zod suele ser una combinación bien sólida.
5) ¿Qué hago si mi app se siente lenta?
Primero perfila. Luego revisa:
- renders en cascada por estado global mal puesto
- listas grandes sin virtualización
- componentes pesados sin memoización donde sí aplica
- imágenes y bundles (code splitting)
Siguiente episodio
La rebelión no siempre es brincar a otro framework; a veces es agarrar herramientas que te quitan dolor.
El próximo tiro: Next.js vs “React puro”. Cuándo el framework te salva… y cuándo te mete en un laberinto.
Idea para cerrar bien este post: toma una sola práctica de aquí y conviértela en algo que tu equipo pueda aplicar hoy.
Cuando un artículo aterriza en decisiones reales, deja de ser contenido y se vuelve ventaja.


