Versiones
Qué cambió, y por qué te importa
Correr el mismo código en dos versiones al mismo tiempo y contar los commits vale más que leer diez notas de lanzamiento. Los números que ves los reporta el Profiler de React de cada versión.
Dos setState dentro de un setTimeout. Contá los commits en React 17 y después en 18: ahí está el batching automático.
bajando React 17.0.2 de esm.sh…
Sin actividad todavía.
La versión sin novedades
bajando React 19.2.0 de esm.sh…
Sin actividad todavía.
Acciones, use() y ref como prop
Las cuatro versiones que importan
2019
React 16.8
Llegan los hooks
El estado deja de necesitar clases. Aparece la cadena de hooks colgada del fiber, que sigue siendo la misma estructura hasta hoy. El batching existe, pero sólo dentro de manejadores de eventos.
2020
React 17
La versión sin novedades
Cero funcionalidades nuevas a propósito. Cambian el sistema de eventos (se delegan al contenedor raíz y no a document) y se prepara el terreno para poder tener dos versiones de React conviviendo. Es una versión puente.
2022
React 18
Concurrencia y batching automático
createRoot habilita el renderizado concurrente. El batching automático agrupa updates en cualquier contexto, no sólo en eventos. Llegan useTransition, useDeferredValue, useId y useSyncExternalStore. StrictMode empieza a montar dos veces en desarrollo.
2024
React 19
Acciones, use() y ref como prop
Las Actions integran estados de envío y error en formularios. use() lee promesas y contexto con reglas nuevas. ref pasa a ser una prop común y forwardRef deja de hacer falta. Los metadatos del documento se pueden declarar desde cualquier componente.
Diferencia por diferencia
No es una lista de funcionalidades: son las preguntas que aparecen cuando migrás una app de verdad.
| Pregunta | React 16.8 | React 17 | React 18 | React 19 |
|---|---|---|---|---|
| BatchingDos setState dentro de un setTimeout, ¿cuántos renders?Hasta React 17 el lote se abría sólo dentro de manejadores de eventos sintéticos. Desde 18, createRoot abre lote en cualquier contexto: timeouts, promesas, efectos y código nativo. Es el batching automático. | 2 renders | 2 renders | 1 render | 1 render |
| Montaje de la raíz¿Cómo se monta la aplicación?createRoot es lo que habilita el renderizado concurrente. Con ReactDOM.render, React 18 corre en modo legacy y no tenés ni batching automático ni transiciones, aunque la versión instalada sea la 18. | ReactDOM.render(el, nodo) | ReactDOM.render(el, nodo) | createRoot(nodo).render(el) | createRoot(nodo).render(el) |
| StrictMode en desarrollo¿Cuántas veces corre un useEffect al montar?Desde React 18, StrictMode simula un desmontaje y un remontaje para verificar que tus efectos sean idempotentes. Si tu efecto no sobrevive a ese ciclo, le falta el cleanup. Sólo pasa en desarrollo. | 1 vez | 1 vez | 2 veces (monta, desmonta, monta) | 2 veces (monta, desmonta, monta) |
| Estados de formulario¿Cómo se maneja «enviando…» y el error de un submit?React 19 integra las Actions: le pasás una función asincrónica a la prop action de un form y React se encarga del estado pendiente, el error y el reseteo. Antes había que cablear tres useState por formulario. | a mano, con useState | a mano, con useState | a mano, o con useTransition | useActionState + useFormStatus |
| Reenviar refs¿Cómo recibe una ref un componente de función?En React 19 ref es una prop más y llega en el objeto de props. forwardRef sigue funcionando pero quedó obsoleto: era un envoltorio necesario sólo porque ref estaba reservada. | forwardRef | forwardRef | forwardRef | ref como prop común |
| Leer una promesa en el render¿Se puede consumir una promesa desde un componente?use() no es un hook común: se puede llamar dentro de condicionales, porque no ocupa lugar en la cadena. Suspende el componente hasta que la promesa se resuelva y también sirve para leer contexto. | no | no | sólo con librerías compatibles con Suspense | use(promesa) |
| Metadatos del documento¿Desde dónde se setean title y meta?React 19 sube automáticamente esas etiquetas al head, las renderiza del lado del servidor y las deduplica. Para la mayoría de las apps, deja de hacer falta una librería aparte. | librería externa | librería externa | librería externa | <title> y <meta> en cualquier componente |
| Errores de hidratación¿Qué te dice React cuando el HTML del servidor no coincide?React 19 junta todas las discrepancias en un solo mensaje que muestra qué esperaba y qué encontró. Diagnosticar un problema de hidratación pasó de arqueología a lectura. | advertencia genérica | advertencia genérica | un error por diferencia | una diferencia unificada con el árbol |
Las versiones se bajan de esm.sh en su build de desarrollo, que es el único que emite advertencias, activa el Profiler y hace que StrictMode monte dos veces. Es exactamente lo que corrés en tu máquina mientras desarrollás. Probá tu propio código en el playground.