¿Qué viene en React 18? – CloudSavvy TI

Reaccionar logotipo sobre un fondo oscuro

React 18 será la próxima versión principal de la popular biblioteca de componentes de JavaScript. Ahora disponible como un candidato de lanzamientointroduce varios cambios para mejorar la obtención de datos, el rendimiento y la representación del lado del servidor.

Para aprovechar todas las funciones, deberá actualizar su proyecto y es posible que encuentre algunos cambios importantes. Sin embargo, React 18 sigue siendo generalmente compatible con códigos anteriores. Debería poder actualizar la versión de lanzamiento en su package.json sin enfrentar demasiados problemas inmediatos.

Representación concurrente

La motivación detrás de la mayoría de las revisiones de React 18 se refiere a algo llamado «representación concurrente». Este mecanismo le da a React una forma de ensamblar múltiples versiones de su árbol de componentes simultáneamente. Si bien los detalles de esto solo son relevantes para las funciones internas de la biblioteca, el resultado es una mayor flexibilidad y un rendimiento mejorado para su aplicación.

Renderizado concurrente hace que el proceso de renderizado sea interrumpible. Mientras que un renderizado en React 17 debe ejecutarse hasta su finalización una vez que comienza, React 18 proporciona una forma de pausar a la mitad y reanudarlo más tarde.

Esta capacidad significa que es menos probable que los renderizados de React afecten el rendimiento general del navegador. Hasta ahora, los eventos del navegador, como presionar teclas y pintar, estaban bloqueados mientras se procesaba. Con el renderizado simultáneo habilitado, una pulsación de tecla interrumpirá el renderizado, permitirá que el navegador maneje el cambio y luego reanude el renderizado.

Esto da como resultado una experiencia de usuario más fluida que es menos susceptible al tartamudeo cuando el renderizado coincide con otras actividades. React mantiene múltiples ramas de trabajo; una vez que se completa la representación de una rama, lo que puede ocurrir en varias sesiones distintas, se acepta en la rama principal que produce la interfaz de usuario visible.

Modo concurrente frente a renderizado concurrente

Antes de que React 18 alcanzara el estado alfa, esta función se denominaba «modo concurrente». Es posible que aún vea este nombre en artículos y documentación más antiguos. El concepto de renderizado simultáneo como un modo separado ya no existe en React 18. Esto facilita que las aplicaciones existentes pasen al nuevo enfoque.

El renderizado concurrente es fundamentalmente diferente al sistema de renderizado existente. Tiene una API completamente nueva que reemplaza la conocida ReactDOM.render(). En los días del modo simultáneo, la simultaneidad era todo o nada: estaba habilitada para su aplicación, con la perspectiva de cambios importantes importantes, o completamente fuera de los límites. Ahora se maneja con más gracia con React que solo aplica renderizado simultáneo a las actualizaciones de DOM que en realidad requieren una función concurrente.

La nueva API raíz (activación del modo concurrente)

Las aplicaciones existentes actualizadas a React 18 pueden seguir usándose ReactDOM.render() en el futuro inmediato. Esto renderizará su aplicación sin soporte de concurrencia, utilizando el renderizador familiar de v17. Verá una advertencia en la consola de que la API ya no es compatible, pero esto puede ignorarse mientras realiza la actualización.

import App from "./App.js";
import ReactDOM from "react-dom";
 
// "ReactDOM.render is no longer supported in React 18"
ReactDOM.render(<App />, document.getElementById("root"));

Para eliminar la advertencia, cambie a la nueva createRoot() API:

import {createRoot} from "react-dom/client";
const root = createRoot(document.getElementById("root"));
root.render(<App />);

createRoot() devuelve un nuevo objeto raíz que representa una superficie de renderizado de React. Puedes llamar a su render() método para renderizar un componente React a la raíz. El resultado del código anterior es el mismo que el anterior. ReactDOM.render() ejemplo. createRoot() es una interfaz más orientada a objetos con una facilidad de uso mejorada.

Raíces producidas por createRoot() soporte de renderizado concurrente. La actualización a esta API le brinda acceso opcional a las nuevas capacidades de React 18.

los createRoot() equivalente de ReactDOM.unmountComponentAtNode() Es el nuevo unmount() método expuesto en los objetos raíz. Puede usar esto para separar su árbol de componentes de React y dejar de renderizar su aplicación:

import App from "./App.js";
import ReactDOM from "react-dom";
 
// OLD
ReactDOM.unmountComponentAtNode(document.getElementById("root"));
 
// NEW
const root = createRoot(document.getElementById("root"));
root.unmount();

Características concurrentes

La representación simultánea le permite usar funciones simultáneas para mejorar el rendimiento de su aplicación. Estas son algunas de las API clave disponibles.

Suspenso

los <Suspense> El componente existe desde React 16. Le permite evitar que los elementos secundarios de un componente se representen hasta que se cumpla una condición. Se usa comúnmente para la obtención de datos y la importación de módulos asincrónicos.

const fetchPostHistory = id => fetch(`/users/${id}/posts`);
 
const UserCard = ({Id, Name}) => {
 
    const [postHistory] = useState(() => fetchPostHistory(Id));
 
    <div>
        <h1>{Name}</h1>
        <React.Suspense fallback="Loading...">
            <UserPostHistoryList posts={postHistory} />
            <ReportUserLink id={Id} />
        </React.Suspense>
    </div>
};

En este ejemplo, ni el UserPostHistory o ReportUserLink los componentes aparecerán hasta que los datos del historial de publicaciones del usuario se obtengan de la red. Esto ya funciona bien en muchas situaciones, pero la implementación de React 17 tiene algunas peculiaridades.

Si registró los efectos de cada componente, vería el ReportUserLink El componente se representó mientras las publicaciones aún se estaban cargando, aunque no es visible en ese momento. Usando la explicación de la concurrencia de antes, es posible explicar por qué: una vez que React comenzó a representar el árbol de componentes, no tenía forma de detenerse, aunque un humano puede detectarlo. ReportUserLink es redundante hasta postHistory está poblada.

El suspenso es más poderoso en React 18. La nueva versión se llama “Concurrent Suspense”; la implementación anterior ahora se conoce como Legacy Suspense. Resuelve el problema del ejemplo anterior: renderizar el mismo código con la concurrencia habilitada evitará que el renderizador alcance <ReportUserLink> mientras la obtención de datos está en curso.

Registrar los efectos de cada componente mostraría que ReportUserLink solo se compromete una vez que el historial de publicaciones está disponible. React interrumpe el render cuando llega UserPostHistoryList y necesita esperar a que se carguen los datos. Una vez que se completa la llamada de red, React continúa representando el resto del subárbol de Suspense.

Esta capacidad ayuda a evitar el desperdicio de trabajo del que sus usuarios nunca se benefician. También resuelve varios problemas con Suspense donde los componentes pueden haber ejecutado efectos antes de lo esperado. Finalmente, esta solución brinda una garantía automática de que los datos llegarán en el orden en que fueron solicitados. No necesita preocuparse por las condiciones de carrera, ya que el procesamiento se interrumpe mientras se recuperan los datos.

Transiciones

Las transiciones son una nueva característica habilitada concurrentemente. Esta API es una forma de señalar a React las prioridades relativas de las actualizaciones de la interfaz de usuario. Una «transición» es una actualización de prioridad relativamente baja, como cambiar entre pantallas principales. Las actualizaciones, como las representaciones en respuesta a la entrada del teclado y otras interacciones del usuario, se consideran más urgentes.

Marcar una actualización como una transición tiene algunos efectos sobre cómo React aborda su cumplimiento. React utilizará las capacidades de representación interrumpible de la concurrencia para pausar la actualización si aparece una más urgente a mitad de camino. Esto ayudará a que su interfaz de usuario responda a la entrada del usuario mientras el renderizado está en curso, reduciendo la tartamudez y el bloqueo.

Las transiciones son útiles en una amplia gama de situaciones: actualizar un panel de notificaciones en el encabezado de su aplicación, administrar actualizaciones en su barra lateral y cambiar otras funciones auxiliares de su interfaz de usuario son buenos candidatos. También funcionan bien para acciones asincrónicas realizadas en respuesta a la entrada del usuario, como el caso clásico de una barra de búsqueda que se actualiza a medida que el usuario escribe.

Esto puede ser difícil de hacer bien en React: sin un antirrebote cuidadoso, es común sentir un retraso perceptible ya que las actualizaciones causadas por la obtención de nuevos resultados bloquean temporalmente el hilo principal para que no maneje la entrada del teclado. Con React 18, puede usar una transición para marcar esas actualizaciones como trabajo de baja prioridad.

los startTransition() La API encapsula las actualizaciones de estado como transiciones:

import {startTransition} from "react";
 
const Component = () => {
 
    const [searchQuery, setSearchQuery] = useState("");
    const [searchResults, setSearchResults] = useState({});
 
    /**
     * State updates within the transition function are low-priority
     */
    startTransition(() => {
        setSearchResults({text: "Search Result 1"});
    });
 
};

Si desea verificar si hay una actualización en curso, reemplace simple startTransition() con el useTransition() gancho. Esto le da un valor booleano que indica si una transición tiene trabajo pendiente.

import {useTransition} from "react";
 
const Component = () => {
 
    const [searchQuery, setSearchQuery] = useState("");
    const [searchResults, setSearchResults] = useState({});
 
    const [isSearching, startSearchResultsTransition] = useTransition();
 
    startSearchResultsTransition(() => {
        setSearchResults({text: "Search Result 1"});
    });
 
    return (
        <div>
            <input onChange={setSearchQuery} value={searchQuery} />
            <SearchResults results={searchResults} />
            {(isSearching && "(Searching...)")}
        </div>
    );
 
};

Todas las actualizaciones de estado existentes se tratan como actualizaciones urgentes periódicas para mantener la compatibilidad con el código anterior.

Valores Diferidos

Los valores diferidos son otra forma de mantener la capacidad de respuesta durante las actualizaciones de larga duración. Cuando un valor es diferido por el useDeferredValue() gancho, React seguirá mostrando su viejo valor durante un período determinado.

const Component = () => {
    const [results, setResults] = useState([]);
    const deferredResults = useDeferredResults(results, {timeoutMs: 5000});
    return <ResultsGrid results={deferredResults} />;
};

Permitir que React siga mostrando los resultados anteriores durante cinco segundos evita la ralentización al eliminar la necesidad de procesar inmediatamente los datos obtenidos tan pronto como llegan. Es una forma de antirrebote que está integrada en la gestión de estado de React. Los datos pueden retrasarse unos segundos con respecto al estado real para reducir la cantidad total de trabajo realizado.

Mejor procesamiento por lotes

Un cambio final orientado al rendimiento en React 18 consiste en un conjunto de mejoras en el procesamiento por lotes de actualizaciones de estado. React ya intenta combinar actualizaciones de estado en varias situaciones simples:

const Component = () => {
 
    const [query, setQuery] = useState("");
    const [queryCount, setQueryCount] = useState("");
 
    /**
     * Two state updates, only one re-render
     */
    setQuery("demo");
    setQueryCount(queryCount + 1);
 
};

Sin embargo, hay varias situaciones en las que esto no funciona. A partir de React 18, el procesamiento por lotes se aplica a todos actualizaciones, independientemente de su procedencia. Las actualizaciones que se originan a partir de tiempos de espera, promesas y controladores de eventos del navegador se agruparán por lotes de la misma manera que el código que está directamente dentro de su componente.

Este cambio puede alterar el comportamiento de algunos códigos. Si tiene un componente antiguo que actualiza el estado varias veces en los lugares enumerados anteriormente, luego verifica los valores a la mitad, es posible que no sean lo que esperaba en React 18. flushSync El método está disponible para forzar manualmente la confirmación de una actualización de estado, lo que le permite optar por no participar en el procesamiento por lotes.

const Component = () => {
 
    const [query, setQuery] = useState("");
    const [queryCount, setQueryCount] = useState("");
 
    const handleSearch = query => {
       fetch(query).then(() => {
 
            /**
             * Force commit and update the DOM
             */
            flushSync(() => setQuery(query));
 
            setQueryCount(1);
 
        });
    }
 
};

Cambios en la representación del lado del servidor

La representación del lado del servidor se ha revisado en gran medida. La nueva característica principal es la compatibilidad con el procesamiento de transmisión, donde el nuevo HTML se puede transmitir desde el servidor a su cliente React. Esto le permite usar componentes de Suspense en el lado del servidor.

Como consecuencia de este cambio, varias API han quedado en desuso o se han reelaborado, incluso renderToNodeStream(). Ahora deberías usar renderToPipeableStream() o renderToReadableStream() para entregar contenido del lado del servidor que sea compatible con los entornos de transmisión modernos.

La hidratación del lado del cliente del contenido renderizado por el servidor también ha cambiado para alinearse con la nueva API de renderizado concurrente. Si está utilizando la representación del servidor y el modo concurrente, reemplace hydrate() con hydrateRoot():

// OLD
import {hydrate} from "react-dom";
hydrate(<App />, document.getElementById("root"));
 
// NEW
import {hydrateRoot} from "react-dom/client";
hydrateRoot(document.getElementById("root"), <App />);

Los efectos del renderizado de transmisión hacen que el renderizado de servidor sea más adecuado para diversos casos de uso. La implementación existente de React del lado del servidor requiere que el cliente obtenga e hidrate toda la aplicación antes de que se vuelva interactiva. Al agregar secuencias y Suspense, React solo puede buscar los bits necesarios para el renderizado inicial, luego cargue datos adicionales no esenciales del servidor después de que la aplicación se vuelva interactiva.

Conclusión

React 18 trae nuevas funciones y mejoras de rendimiento para sus aplicaciones. Capacidades como Suspenso y Transiciones hacen que varios tipos de código sean más fáciles de escribir y menos impactantes en otras áreas de su aplicación.

Actualizar a React 18 cuando se lance debería ser bastante sencillo en la mayoría de los casos. Puede seguir usando la API raíz de React 17 por el momento antes de pasar a createRoot() cuando esté listo para adoptar el renderizado simultáneo. Si desea comenzar a preparar su aplicación hoy, puede instalar la versión candidata más reciente ejecutando npm install react@rc react-dom@rc.

Deja un comentario

En esta web usamos cookies para personalizar tu experiencia de usuario.    Política de cookies
Privacidad