<Arquitectura Javascript> <React 19> <Compilador React>
El objetivo de este post no es explicar detalladamente todos los cambios que vienen con la nueva versión de React recién publicada, sino resumir o listar dichos cambios centrándonos con ejemplos prácticos en los que considero más relevantes, indicados más abajo en la sección "Lo nuevo".
En la documentación oficial, los cambios aparecen divididos en enlaces distintos. Vamos a tratar de tener todos los cambios aquí centralizados, aportando los enlaces a su documentación oficial. Para poder realizar pruebas con casos prácticos de los cambios más relevantes vamos a apoyarnos en este repositorio de GitHub, de manera que podamos entender algo mejor el alcance
También dedicaremos una breve introducción al compilador de React, actualmente está en una versión beta. Creo que sí es importante aclarar que dicho compilador no vendrá necesariamente con la versión 19, sino que esta es la versión mínima con la que dicho compilador en principio iba a funcionar. Recientemente, se publicó este post en el que el equipo de React confirmó que también iban a estar soportadas las versiones 17 y 18 de la librería.
Uso de los ejemplos de este repositorio
Este repositorio contiene varios ejemplos que muestran algunas de las novedades que vienen con la versión 19 de React y del futuro compilador, para poder ver estas características fácilmente de manera práctica.
En concreto, las versiones de React y del compilador que se están utilizando son las que vienen marcadas en el package.json, que son la 19 y la 0.0.0-experimental-487cb0e-20240529 respectivamente
Los ejemplos se cargan en el fichero src/App.tsx. En este fichero hay unas líneas de comentario en la parte superior, que relacionan cada ejemplo con el componente concreto. En concreto son:
- Ejemplo 1: UserTransition -> Ejemplo de useTransition
- Ejemplo 2: UserActionState -> Ejemplo de useActionState
- Ejemplo 3: UserActionStateWithFooter -> Ejemplo de useFormState
- Ejemplos use: UsersManager
- Ejemplo custom elements: EditableList
- Ejemplo metadata: Metadata
- Ejemplo Compilador de react: CompilerTest
Simplemente, debe sustituirse el componente que se quiera probar por el de cada ejemplo y que quede reflejado en el componente Example de dicho componente App. Por ejemplo, si queremos probar el nuevo hook useActionState basta con hacer lo siguiente:
import {UserActionState as Example} from "components";
No obstante, en este documento se indicará para cada caso práctico cual es el componente que se deberá importar.
Arranque de los ejemplos
Para iniciar la aplicación de ejemplos, la cúal ha sido creada basándonos en Vite con el template para React con TS, debemos instalar las dependencias y ejecutar el comando de ejecución:
npm install
npm run dev
Ahora sí, vamos con el resumen de los cambios que vendrán con React 19. Para las características obsoletas o breaking changes, debido sobre todo a características eliminadas que ya quedaron previamente obsoletas, vamos a indicar los enlaces a la documentación oficial. A continuación, indicaremos lo nuevo de React 19, donde se indicarán los ejemplos de lo más relevante para poder practicar con dichas características.
Pero, si lo prefieres, también puedes ejecutarlo en [este codesandbox].(https://codesandbox.io/p/github/madelavega/react19/main?import=true)
Breaking changes
Características eliminadas :
- Eliminados propTypes y defaultProps para funciones
- Eliminado el antiguo contexto que ya quedó obsoleto en react 16.6.0
- Eliminadas referencias como strings en componentes de clases
- Eliminado: Module pattern factories
- Eliminado: createFactory
- Eliminado: react-test-renderer/shallow: ahora se importa directamente con su propio módulo: react-shallow-renderer
- Movido: Se ha movido act al módulo de react directamente, eliminándolo de react-dom/test-utils
- Eliminado método render de react-dom
- Eliminado método hydrate de react-dom
- Eliminado unmountComponentAtNode de react-dom
- Eliminado método findDOMNode de react-dom
Características que pasan a marcarse como obsoletas
- element.ref: deja de tener sentido, al ser ref ahora una propiedad de los componentes
- react-test-renderer: la recomendación oficial: usar React Testing Library.
Otros cambios menores
- Otra lista de cambios quizá algo menos relevantes como para centrarnos en ellos son relativos a cómo exporta React, cambios de tipados, etc. aunque teneís una lista de los mismos aquí
Ahora sí, vamos con los cambios más relevantes...
Lo nuevo :)
Soporte para formularios
En cuanto a características nuevas, cabe destacar un mayor soporte de manera nativa para trabajar con formularios. La etiqueta form ya no se traduce en un nodo nativo de HTML, sino que react-dom realiza su propia implementación para facilitar el manejo de formularios.
Se han introducido nuevos hooks (useActionState, useFormStatus, useOptimistic) para facilitar el manejo de formularios. En este repositorio se han elaborado unos ejemplos básicos para ver las capacidades de estos hooks.
- Ejemplo de acciones asíncronas con useTransition: aunque es un hook introducido en react 18, en React 19 añade soporte para el manejo de funciones asíncronas. Para ver este ejemplo, importar el componente /components/examples/forms/example1/UserTransition.tsx en el App.jsx
- Ejemplo de useActionState: Recibe como parámetro la función asíncrona que queremos invocar al realizar el submit del formulario. A su vez, nos devuelve dicha función así como un estado de pendiente mientras la misma se está procesando. Digamos que evoluciona el hook anterior par gestionar formularios. Para ver un ejemplo, importa en el App.tsx el componente /components/examples/forms/example2/UserActionState.tsx. En la documentación que se enlaza, no está la última versión del hook, por lo que aporto este enlace también
- Ejemplo de useFormStatus: también tenemos un ejemplo de este nuevo hook, importando el componente /components/examples/forms/example3/UserActionState.tsx. Nos sirve para poder subdividir un formulario con más componentes, pero desde dentro de estos acceder al estado del formulario. Observar que el hook se utiliza en un hijo de este componente: en el Footer.tsx
- Hook useOptimistic. Con este hook podemos establecer un estado con un valor que estamos a la espera de confirmación de ser persistido.
Nueva api use
- Nos permite invocar a una promesa mediante use junto con suspense, pudiendo mostrar el componente de fallback mientras termina la carga de dicha promesa. Para probarlo, importar en el App.tsx el componente /examples/use/example1/UsersManager.tsx. Este ejemplo hace uso de un método que devuelve una promesa con un listado de usuarios, para simular una llamada a backend.
- También podemos utilizar use para invocar Context de manera condicional. Actualmente, si existe cualquier contexto que queramos utilizar mediante useContext no podemos usarlo dentro de, por ejemplo, una condición ya que fallará. Con use, podemos utilizar un contexto dentro de cualquier condición.
Soporte para Custom Elements
Vamos a tener soporte para usar customElements con React 19.
Hasta ahora, podíamos utilizar customElements por medio de referencias al nodo del DOM y, mediante esta referencia, cambiar los atributos. Ya no será necesaria esta técnica para poder combinar customElements con React.
Podemos ver un ejemplo de uso de custom element usando el componente /examples/customElements/EditableList.tsx en el App.tsx y
aquí tenemos el roadmap que se estableció para dar soporte a los Custom Elements.
React Server Components
- React 19 soporta Server componentes de manera nativa(https://react.dev/reference/rsc/server-components).
- Los server components pueden ser procesados en tiempo de construcción y/o de ejecución, utilizando un servidor web con frameworks que soporten server componentes como Nextjs o Remix.
- Las librerías pueden exportar el contenido tanto para ser usados como server o client components, mediante la condición de exportación react-server que se configura en el package.json de dichas librerías.
- directivas:
- use server: para server actions (NO para server components)
- use client: para indicar que son componentes de cliente
- Toda la documentación sobre server componentes está [aquí]
Otras Mejoras en React
- Ya no es necesario usar forwardRef. Se han adaptado los componentes para que puedan recibir directamente la propiedad ref
- Mejoras en feedback de errores de hidratación
- Context como provider: ya no es necesario usar un contexto con la etiqueta <MiContexto.Provider>, sino que podemos usar directamente <MiContexto>
- Se añade al hook useDeferredValue la posibilidad de que tenga un valor inicial
- Podemos pasarle a un componente como ref una función, cuya función de retorno nos permite ejecutar acciones de limpieza en el desmontado. Por ejemplo, si tenemos asociado un evento a un nodo del DOM asociado a esta referencia, podemos describirnos en esta función de retorno.
- Soporte a los metadatos del documento HTML.
- Metadatos: Hasta ahora, para poder manejar metadatos del documento HTML, hacíamos uso de librerías externas como react-helmet. Para casos sencillos, ahora tenemos soporte nativo para realizar estas operaciones. Para hacer una prueba, importar el componente /examples/misc/metadata/Metadata.tsx en el App.tsx.
- De igual manera, podemos usar etiquetas link o style dentro de un componente para importar hojas de estilos
- scripts: También podemos cargar scripts de manera asíncrona en un componente
- precargas de recursos: también podemos hacer precargas de recursos mediante ciertos métodos que nos brinda react-dom
- Mejoras en informes de errores. Se eliminan errores duplicados
Compilador de React
Lo primero, aclarar que el compilador de react NO es una característica de React 19. Se puede terminar liberando la versión estable a lo largo de la vida de esta versión o en una versión posterior.
Igualmente, como se trata de una herramienta muy interesante, vamos a ver un caso práctico de su uso y cómo afecta a la hora de construir una aplicación.
- Para comprobar que nuestro código es compatible con el compilador, debemos hacer una comprobación del mismo utilizando la herramienta react-compiler-healthcheck. Ejecutamos:
npx react-compiler-healthcheck@latest
- Instalamos y configuramos los plugins de eslint:
npm install eslint-plugin-react-compiler
En nuestro .eslintrc.cjs hemos añadido:
plugins: [
'eslint-plugin-react-compiler',
...
],
rules: {
'react-compiler/react-compiler': "error",
...
},
- Instalamos el plugin de Babel
npm install babel-plugin-react-compiler
- Configuramos Vite en nuestro caso para hacer uso de dicho plugin. Para ello, tenemos en el vite.config.ts lo siguiente:
react({
babel: {
plugins: [
[
"babel-plugin-react-compiler",
//objeto de configuración del compilador. Ver https://react.dev/learn/react-compiler#using-the-compiler-effectively
{}
],
],
},
})
- Esta configuración del plugin de react en el fichero vite.config.ts podemos comentarla y descomentarla para ver el efecto que tiene.
Para probar el compilador, podemos cargar en el App.jsx el componente /examples/compiler/basic/CompilerTest y realizar un profile con el profiler de react y comprobar cuántos renderizados realiza el componente Footer usando el compilador de React o sin él. Veremos además en el profiler que cuando usamos el compilador de React queda automáticamente memorizado.
En este ejemplo disponemos de un componente que se rerrenderiza cada segundo actualizando un contador y que contiene un componente hijo Footer. Podemos ver la diferencia en cuanto a rerrenderizados, sin necesidad de usar React.memo, usando el compilador y sin usarlo.
- sin compilador: vemos como se rerrenderiza el Footer cada vez que se rerrenderiza el padre:
- con el compilador: vemos como se memoriza el componente en el profiler
Y si has llegado hasta squí, darte las gracias por dedicar tu tiempo en echar un vistazo a este post y espero que te sirva de ayuda para adaptarte a esta nueva versión, entendiendo como estos cambios van a cambiar nuestros desarrollos con React.
Habrá que ver cómo se adaptan también muchas librerías que solemos utilizar actualmente, como React Hook Form para manejo de formularios o la propia React Helment entre otras.