División de código con React.lazy y Suspense

Nunca debes enviar más código de lo necesario a tus usuarios, así que divide tus paquetes para asegurarte de que esto nunca suceda.

El método React.lazy facilita la división de código de una aplicación de React en un a nivel de componente con importaciones dinámicas.

import React, { lazy } from 'react';

const AvatarComponent = lazy(() => import('./AvatarComponent'));

const DetailsComponent = () => (
  <div>
    <AvatarComponent />
  </div>
)

¿Por qué es útil?

Por lo general, una aplicación de React grande constará de muchos componentes, herramientas y bibliotecas de terceros. Si no se hace un esfuerzo para intentar cargar distintas partes de una aplicación solo cuando son necesarias, una sola aplicación de JavaScript se enviará a tus usuarios en cuanto carguen la primera página. Esto puede afectar significativamente el rendimiento de la página.

La función React.lazy proporciona una forma integrada de separar componentes en un en fragmentos separados de JavaScript con muy poco trabajo. Puedes y, luego, controlar los estados de carga cuando la vinculas con Suspense este componente.

Suspense

El problema de enviar una gran carga útil de JavaScript a los usuarios es la longitud el tiempo que tardaría la página en terminar de cargarse, especialmente en dispositivos más débiles y conexiones de red. Por eso, la división de código y la carga diferida extremadamente útil.

Sin embargo, siempre habrá un ligero retraso que los usuarios deberán experimentar cuando se recupera un componente de división de código a través de la red, por lo que es importante mostrar un estado de carga útil. Usa React.lazy con 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 componente fallback que te permite mostrar cualquier tipo de como estado de carga. En el siguiente ejemplo, se muestra cómo funciona. El avatar solo se renderiza cuando se hace clic en el botón, cuando se hace una solicitud Luego, se hace para recuperar el código necesario para el AvatarComponent suspendido. Mientras tanto, se muestra el componente de carga de resguardo.

Aquí, el código que compone AvatarComponent es pequeño, lo que por qué el ícono giratorio de carga solo se muestra por un período breve Más grande puede demorar mucho más en cargarse, especialmente en conexiones de red débiles.

Para demostrar mejor cómo funciona, haz lo siguiente:

  • Para obtener una vista previa del sitio, presiona Ver app. Luego, presiona Pantalla completa pantalla completa
  • Presiona `Control + Mayúsculas + J` (o `Command + Option + J` en Mac) para abrir Herramientas para desarrolladores.
  • Haga clic en la pestaña Red.
  • Haz clic en el menú desplegable Regulación, que está configurado en Sin limitación de forma predeterminada. Selecciona 3G rápida.
  • Haz clic en el botón Click Me en la app.

El indicador de carga se mostrará por más tiempo. ¿Observas cómo todo el código que conforma el AvatarComponent se recupera como un fragmento separado.

Panel de red de Herramientas para desarrolladores que muestra la descarga de un archivo thread.js

Cómo suspender varios componentes

Otra función de Suspense es que te permite suspender varias de la carga de los componentes, incluso si son de 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 y, al mismo tiempo, y solo muestra un único estado de carga. Una vez que todos los componentes hayan terminado el usuario puede verlos todos al mismo tiempo.

Puedes ver esto con la siguiente incorporación:

Sin esto, es fácil encontrarte con el problema de la carga escalonada. diferentes partes de una IU que se cargan una tras otra, cada una con sus propias indicador de carga de trabajo. Esto puede hacer que la experiencia del usuario se sienta más molesta.

Soluciona errores de carga

Suspense te permite mostrar un estado de carga temporal mientras la red se realizan de forma interna. Pero ¿qué sucede si esas solicitudes de red fallan por algún motivo? Es posible que no tengas conexión o que tu aplicación web esté intentando realizar una carga diferida de una URL con versión que esté desactualizada y ya no esté disponible tras la reimplementación del servidor.

React tiene un patrón estándar para manejar correctamente estos tipos de carga. fallas: con un límite de error. Como se describe en la documentación, Cualquier componente de React puede servir como límite de error si implementa uno de estos métodos (o ambos) de los métodos de ciclo de vida static getDerivedStateFromError() o componentDidCatch()

Para detectar y manejar las fallas de carga diferida, puedes unir tu Suspense. con un componente superior que sirva como límite de error. Dentro del método render() del límite de error, puedes renderizar los elementos secundarios tal como están si un error o muestra 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 sabes por dónde comenzar a aplicar la división de código en React sigue estos pasos:

  1. Comienza a nivel de la ruta. Las rutas son la forma más sencilla de identificar tu aplicación que se puede dividir. El Documentos de reacciones mostrar cómo se puede usar Suspense junto con react-router
  2. Identifica los componentes grandes de una página de tu sitio que solo se renderizan en ciertas interacciones del usuario (como hacer clic en un botón). Dividiendo estas minimizará las cargas útiles de JavaScript.
  3. Considera dividir todo lo que esté fuera de la pantalla y no sea crítico para el usuario.