El curso usa React 19.3, la última versión estable. React no tiene versiones LTS: su política solo promete parches de seguridad para las versiones mayores afectadas. Hoy reciben parches las líneas 19.0, 19.1, 19.2 y 19.3, y la mayor anterior es la 18.3.
Esta página reúne todos los apartados del curso que dependen de la versión. Si tu proyecto o tu centro usan una versión anterior, sabrás qué no tendrás y qué hacer en su lugar. La versión indicada es en la que apareció cada cosa, de modo que también te sirve si usas 19.0, 19.1 o 19.2.
Marca
Significado
🆕
Es nuevo en esa versión: no existe en las anteriores
🔄
Ya existía, pero cambia en esa versión
⚠️ Importante: React Router 8 exige React 19.2.7 o superior. Con una versión anterior tienes que usar React Router 7, como explica el módulo 18.
Resumen
El curso tiene 138 apartados que dependen de la versión, en 25 módulos.
Gestiona el envío de formularios con useState para el estado pendiente y los errores, usa forwardRef para pasar refs, <Contexto.Provider> como proveedor, y useContext en lugar de use. Los Server Components no tienen alternativa.
Usa la pila de componentes errorInfo.componentStack que reciben los Error Boundaries, y las herramientas de desarrollo. Pierdes poder pedir esa pila en cualquier punto del código.
En lugar de <Activity>, renderiza de forma condicional, perdiendo el estado, u oculta con CSS, sin parar los efectos. En lugar de useEffectEvent, guarda el último valor en una ref. cacheSignal y Performance Tracks no tienen alternativa directa.
Para animar, usa document.startViewTransition con flushSync, o la biblioteca Motion. En lugar de <Fragment ref>, añade un elemento contenedor. En lugar de browser(), muestra el contenido en el cliente tras montar el componente.
En React 19.2 y anteriores una transición lenta puede retener a las demás, y Strict Mode no duplica los efectos durante la hidratación.
No necesitas hacer nada, pero al actualizar revisa el código que dependía de que varias transiciones terminaran juntas, y los efectos que no toleren ejecutarse dos veces.
En React 18.3 el símbolo es react.element y ref es un campo propio del elemento. Desde 19.0 el símbolo es react.transitional.element y ref se lee en element.props.ref.
Lee element.ref. Solo te afecta si inspeccionas elementos a mano, algo que el código normal no debería hacer.
React asigna propiedades a los elementos personalizados (Web Components) si el elemento las define, entiende className y trata true y false como atributos booleanos. En React 18.3 todo se convertía en atributos de texto.
Escribe class en lugar de className y pasa objetos o funciones con un ref y elemento.propiedad = valor.
Envuelve el grupo en un elemento real, como <div style={{ display: 'contents' }} ref={...}>, o usa un ref en cada hijo. No hay equivalente sin un nodo extra.
React bloquea las URL javascript: en atributos como href, src y action: las sustituye por código que lanza un error. En React 18.3 las deja pasar y solo avisa en la consola.
Valida tú cada URL que venga de datos externos con una lista de protocolos permitidos, como hace urlSegura.
React no vuelve a asignar innerHTML si la cadena __html no ha cambiado, aunque el objeto sea nuevo. Hasta 19.2 lo reasignaba en cada render en el que cambiara el objeto, y destruía los nodos internos.
Guarda el objeto { __html } en una constante o con useMemo para que no cambie entre renders.
En React 19.2 y anteriores el evento sintético de submit no tiene submitter: vale undefined.
Lee e.nativeEvent.submitter, que existe en todas las versiones, y con tipos antiguos convierte antes: (e.nativeEvent as globalThis.SubmitEvent).submitter.
Oculta el componente con CSS (hidden) para conservar su estado, sabiendo que sus efectos seguirán activos, o eleva el estado y deja que el componente se destruya.
Usa el atributo hidden, que también conserva el estado, aunque los efectos del panel oculto seguirán activos. En el ejemplo de esta sección, borra el bloque 3 y su importación.
<style> y <link> se quedan en el <body>, se repiten con cada instancia y precedence acaba como atributo sin efecto. Importa el CSS con import o colócalo en index.html, y carga los estilos bajo demanda con import().
<title> y <meta> se quedan en el <body> y el título de la pestaña no cambia. Asigna document.title dentro de un useEffect, o usa una biblioteca que gestione <head>.
Hasta React 19.2, si un <input type="number"> tiene el foco, cambiar defaultValue no actualiza su atributo value; en 19.3 sí lo hace, igual que en los demás tipos de campo.
No cambies defaultValue con el campo enfocado; para reiniciarlo con otro valor, cámbiale la key.
useId genera _r_0_. En 19.1 generaba «r0», y en 19.0 y 18.3 generaba :r0:.
El hook funciona igual, pero si usas el identificador en un selector CSS o en querySelector, escápalo con CSS.escape(id), porque los dos puntos no son válidos en un selector sin escapar.
No existe en React 18.3: allí React avisa con Invalid value for prop action, descarta la función y el navegador envía el formulario recargando la página.
Usa onSubmit con e.preventDefault(), new FormData(e.currentTarget) y un estado enviando, como en la sección 9.
En React 19.0, 19.1 y 19.2, Strict Mode no repite los efectos al hidratar con hydrateRoot ni al remontar un componente con Fast Refresh.
Esos dos casos no te avisarán de una limpieza que falta, así que comprueba el componente también en un árbol creado con createRoot, donde la repetición sí ocurre.
No hay equivalente exacto. Para ocultar una parte de la interfaz sin perder su estado, elévalo a un componente padre o usa display: none; en ese caso los efectos siguen activos.
Este caso usa useEffectEvent, que no existe en React 19.1 ni anteriores.
Sustituye refrescar por una ref actualizada en useLayoutEffect, como en el apartado “Si no tienes React 19.2” de la sección 9. El resto funciona igual.
Con @types/react 18 se podía escribir useRef<number>(), y los tipos distinguían un RefObject de solo lectura y un MutableRefObject. Con los tipos de 19, el argumento es obligatorio y solo queda RefObject, con current siempre modificable.
Pasa siempre un argumento, por ejemplo useRef<number \| undefined>(undefined), que compila en ambas.
: <Fragment ref> da un aviso y la ref no recibe nada.
Añade un envoltorio con ref (en una tabla, un <tbody> por grupo), o un <div style={{ display: 'contents' }}>, que no afecta al diseño; también puedes usar una callback ref por hijo con un Map, como en la sección 4.
Los tipos de @types/react 19 cambian los genéricos de useReducer: ahora son useReducer<Estado, [Accion]>, y ya no useReducer<Reducer<Estado, Accion>>.
Deja que TypeScript infiera los tipos desde el reductor, que funciona igual en ambas versiones. Si necesitas escribirlos a mano con @types/react 18, usa useReducer<Reducer<Estado, Accion>>, y Dispatch<Accion> para tipar dispatch, porque ActionDispatch no existe en esos tipos.
use(Contexto) lee un contexto y admite condiciones y bucles. No existe en React 18.3 ni anteriores: el paquete no exporta use.
Lee con useContext(Contexto) al principio del componente, antes de cualquier return condicional. Se pierde la posibilidad de leer el contexto dentro de condiciones o bucles.
Guarda alClicarFuera en una ref actualizada en useLayoutEffect y llama a ref.current() dentro del efecto, como en la versión compatible de useIntervalo.
El evento submit de React expone submitter con el botón que lo envió.
e.submitter compila con @types/react 19.2.10 o superior, pero en ejecución vale undefined; lee e.nativeEvent.submitter, que funciona en todas las versiones.
useRef necesita un argumento y RefObject deja de ser de solo lectura, aunque se cree con null.
useRef<T>() sin argumento compila, y useRef<T>(null) devuelve un objeto con .current de solo lectura; para escribir en él declara useRef<T \| null>(null).
Los tipos de useReducer cambian: ahora son useReducer<S, A>, donde A es una tupla de argumentos, y aparece ActionDispatch.
Se escribe useReducer<Reducer<Estado, Accion>>. Lo mejor es no escribir parámetros: useReducer(reductor, inicial) compila igual en todas las versiones.
El cliente de react-dom es desde 19.0 un módulo propio, así que el alias se pone sobre react-dom/client.
En React 18, react-dom/client importa internamente react-dom, y el alias exacto se pone sobre react-dom: { find: /^react-dom$/, replacement: 'react-dom/profiling' }.
Los ejemplos de este apartado leen datos con use. La combinación de transición y Suspense ya existe en React 18.3 con lazy o con bibliotecas compatibles.
Aplica estas mismas ideas con lazy, o con useSuspenseQuery de TanStack Query.
Casi todo este módulo depende de las Actions, que no existen en React 18.3 ni anteriores.
Escribe el ciclo a mano con useState, try, catch y finally, como en el primer ejemplo de la sección 1, y actualiza a 19 cuando puedas. Los cambios de 19.1, 19.2 y 19.3 no alteran nada de lo que se enseña aquí: hemos ejecutado las pruebas de comportamiento en 19.0.9, 19.2.9 y 19.3.1 y el resultado coincide.
Usa useReducer o useState más un estado de espera propio, y gestiona a mano el orden de las peticiones. En las versiones canary previas a 19 se llamaba useFormState y estaba en react-dom.
Guarda el valor nuevo con useState antes de la petición, conserva una copia del anterior y restáuralo en el catch. Tendrás que resolver a mano las operaciones que se solapan.
Oculta con style={{ display: 'none' }}, que conserva estado y DOM pero deja los efectos activos, o eleva el estado al padre si te basta con guardar los datos.
Crea tu propio AbortController y llama a abort() cuando sepas que el trabajo ya no sirve. No hay forma directa de enterarse de cuándo acaba el render en servidor.
Llama tú a document.startViewTransition y aplica el cambio dentro con flushSync, como se explica en el apartado 13. Pierdes la integración con transiciones, Suspense y nombres automáticos.
Quita <ViewTransition> y addTransitionType. El panel sigue funcionando sin animaciones desde 19.2, y antes de 19.2 cambia <Activity> por display: none.
Con React 19.2.7 o superior y React Router 8, en React Router 8 middleware es una función estable y context siempre tiene su tipo.
En React Router 7.18 pasa future: { v8_middleware: true } a createBrowserRouter, como pide su documentación, y amplía interface Future para que context no sea any. Los detalles están en la sección 20.
<ViewTransition> no existe en React 19.2 ni anteriores.
Usa la prop viewTransition de <Link>, <NavLink> y <Form>. Está disponible en React Router 7 y 8, aunque en 8.5 quedó obsoleta. Sigue funcionando y no exige React 19.3, pero se apoya en la API de React Router, que algún día desaparecerá.
React Router 8 exige React 19.2.7 y no admite React 19.2.6 ni anteriores.
Instala react-router@7.18.5. Este módulo funciona casi sin cambios: la aplicación EMPRESA se ha recorrido con esa versión sobre React 19.1.10 y 18.3.1, con los mismos resultados.
React Router 8 no se instala en React 19.1 ni anteriores: exige react >= 19.2.7.
El patrón sigue siendo válido sin Router 8, porque solo consiste en llamar a queryClient.query antes de cambiar de pantalla: hazlo en el manejador que cambia de vista, o en onMouseEnter, y deja que el componente lea con useSuspenseQuery.
ref llega como una prop más y {...resto} la entrega al <input>.
Envuelve Entrada con forwardRef<HTMLInputElement, PropsEntrada> y añade ref={ref} al <input>, o register no recibirá el nodo y el campo fallará sin avisar.
react-test-renderer/shallow se elimina, react-dom/test-utils conserva solo act (obsoleto) y el resto de utilidades, como Simulate, desaparece.
En 18.3 esas utilidades aún existen, pero no las uses; escribe las pruebas con Testing Library, que funciona igual en 18.3 y en 19, e importa act de react o de @testing-library/react.
useActionState, useFormStatus y <form action={función}> no existen en React 18.
Escribe el login con onSubmit, useState para el error y otro useState para el estado pendiente. Las pruebas de esta sección valen sin cambios, porque solo miran la pantalla.
Server Components, Server Functions y las directivas 'use client' y 'use server' son estables desde esta versión. No existen como función estable en React 18.3 ni anteriores.
No hay alternativa directa con Vite y una SPA. Puedes hacer SSR clásico con renderToPipeableStream, o usar el Pages Router de Next con getServerSideProps, pero pierdes los Server Components. Con el App Router la versión de tu package.json importa menos de lo que parece, como verás en el apartado 4.
Estas opciones de createRoot no existen en React 18.3 ni anteriores.
Informa de los errores en el componentDidCatch de una Error Boundary que envuelva toda la aplicación, y usa window.addEventListener('error', ...) para el resto.
En React 18.3, ref no llega a un componente función como prop.
Envuelve Campo y Desplegable con forwardRef, como se muestra en la sección 17. Sin ese cambio, React Hook Form no recibe la referencia del <input> y el formulario se envía siempre vacío.
React Router 8 exige React 19.2.7 o superior y Node 22.22 o superior.
Cambia react-router por la versión 7.18.5; con React 19.0 o 19.1 no hay que tocar nada más, y con React 18.3 hay que añadir forwardRef a los dos campos de formulario y sustituir <title> por document.title.