División de código con React.lazy y Suspense
Nunca necesita enviar más código del necesario a sus usuarios, ¡así que divida sus paquetes para asegurarse de que esto nunca suceda!
El React.lazy
facilita la división de código de una aplicación React a nivel de componente mediante importaciones dinámicas.
import React, { lazy } from 'react';
const AvatarComponent = lazy(() => import('./AvatarComponent'));
const DetailsComponent = () => (
<div>
<AvatarComponent />
</div>
)
¿Por qué es útil esto? #
Una aplicación React grande generalmente constará de muchos componentes, métodos de utilidad y bibliotecas de terceros. Si no se hace un esfuerzo para intentar cargar diferentes partes de una aplicación solo cuando son necesarias, se enviará un paquete grande de JavaScript a sus usuarios tan pronto como carguen la primera página. Esto puede afectar significativamente el rendimiento de la página.
La React.lazy
proporciona una forma integrada de separar los componentes de una aplicación en fragmentos separados de JavaScript con muy poco trabajo preliminar. Luego puede encargarse de los estados de carga cuando lo acopla con el componente Suspense
Suspenso #
El problema de enviar una gran carga útil de JavaScript a los usuarios es el tiempo que tardaría la página en terminar de cargarse, especialmente en dispositivos y conexiones de red más débiles. Es por eso que la división de código y la carga diferida son extremadamente útiles.
Sin embargo, siempre habrá un ligero retraso que los usuarios tendrán que experimentar cuando se recupere un componente de código dividido a través de la red, por lo que es importante mostrar un estado de carga útil. El uso de React.lazy
con el Suspense
ayuda a resolver este problema.
import React, { lazy, Suspense } from 'react';
const AvatarComponent = lazy(() => import('./AvatarComponent'));
const renderLoader = () => <p>Loading</p>;
const DetailsComponent = () => (
<Suspense fallback={renderLoader()}>
<AvatarComponent />
</Suspense>
)
Suspense
acepta un fallback
que le permite mostrar cualquier componente de React como un estado de carga. El siguiente ejemplo muestra cómo funciona esto. El avatar solo se procesa cuando se hace clic en el botón, donde se realiza una solicitud para recuperar el código necesario para el AvatarComponent
suspendido. Mientras tanto, se muestra el componente de carga de reserva.
Aquí, el código que compone AvatarComponent
es pequeño, por lo que la ruleta de carga solo se muestra durante un corto período de tiempo. Los componentes más grandes pueden tardar mucho más en cargarse, especialmente en conexiones de red débiles.
Para demostrar mejor cómo funciona esto:
- To preview the site, press View App. Then press Fullscreen
.
- Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.
- Click the Network tab.
- Haga clic en el menú desplegable Throttling , que está configurado en Sin estrangulamiento de forma predeterminada. Seleccione 3G rápido .
- Haga clic en el botón Haga clic en mí en la aplicación.
El indicador de carga se mostrará durante más tiempo. Observe cómo todo el código que forma AvatarComponent
se obtiene como un fragmento separado.
Suspender varios componentes #
Otra característica de Suspense
es que le permite suspender la carga de varios componentes, incluso si todos tienen carga diferida .
Por ejemplo:
import React, { lazy, Suspense } from 'react';
const AvatarComponent = lazy(() => import('./AvatarComponent'));
const InfoComponent = lazy(() => import('./InfoComponent'));
const MoreInfoComponent = lazy(() => import('./MoreInfoComponent'));
const renderLoader = () => <p>Loading</p>;
const DetailsComponent = () => (
<Suspense fallback={renderLoader()}>
<AvatarComponent />
<InfoComponent />
<MoreInfoComponent />
</Suspense>
)
Esta es una forma extremadamente útil de retrasar la representación de varios componentes mientras solo muestra un único estado de carga. Una vez que todos los componentes han terminado de recuperarse, el usuario puede verlos todos mostrados al mismo tiempo.
Puede ver esto con la siguiente inserción:
Sin esto, es fácil encontrarse con el problema de la carga escalonada , o diferentes partes de una interfaz de usuario que se cargan una tras otra y cada una tiene su propio indicador de carga. Esto puede hacer que la experiencia del usuario se sienta más discordante.
Manejar fallas de carga #
Suspense
permite mostrar un estado de carga temporal mientras las solicitudes de red se realizan bajo el capó. Pero, ¿qué pasa si esas solicitudes de red fallan por alguna razón? Es posible que esté desconectado o que su aplicación web esté intentando cargar de forma diferida una URL versionada que está desactualizada y ya no está disponible después de una redistribución del servidor.
React tiene un patrón estándar para manejar con elegancia estos tipos de fallas de carga: usar un límite de error. Como se describe en la documentación , cualquier componente de React puede servir como un límite de error si implementa uno (o ambos) de los métodos del ciclo de vida static getDerivedStateFromError()
o componentDidCatch()
.
Para detectar y manejar fallas de carga diferida, puede envolver su Suspense
con un componente principal que sirva como límite de error. render()
del límite de error, puede representar los elementos secundarios como están si no hay ningún error, o generar un mensaje de error personalizado si algo sale mal:
import React, { lazy, Suspense } from 'react';
const AvatarComponent = lazy(() => import('./AvatarComponent'));
const InfoComponent = lazy(() => import('./InfoComponent'));
const MoreInfoComponent = lazy(() => import('./MoreInfoComponent'));
const renderLoader = () => <p>Loading</p>;
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = {hasError: false};
}
static getDerivedStateFromError(error) {
return {hasError: true};
}
render() {
if (this.state.hasError) {
return <p>Loading failed! Please reload.</p>;
}
return this.props.children;
}
}
const DetailsComponent = () => (
<ErrorBoundary>
<Suspense fallback={renderLoader()}>
<AvatarComponent />
<InfoComponent />
<MoreInfoComponent />
</Suspense>
</ErrorBoundary>
)
Conclusión #
Si no está seguro de dónde comenzar a aplicar la división de código a su aplicación React, siga estos pasos:
- Comience en el nivel de la ruta. Las rutas son la forma más sencilla de identificar puntos de su aplicación que se pueden dividir. Los documentos de React muestran cómo se puede usar
Suspense
react-router
. - Identifique cualquier componente grande en una página de su sitio que solo se muestre en determinadas interacciones del usuario (como hacer clic en un botón). Dividir estos componentes minimizará sus cargas útiles de JavaScript.
- Considere dividir cualquier otra cosa que esté fuera de la pantalla y no sea crítica para el usuario.