Suddivisione del codice con React.lazy e Suspense

Non devi mai inviare agli utenti più codice del necessario, quindi suddividi i bundle per assicurarti che ciò non accada mai.

Il metodo React.lazy semplifica la suddivisione in codice di un'applicazione React a livello di componente utilizzando le importazioni dinamiche.

import React, { lazy } from 'react';

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

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

Perché è utile?

In genere, un'applicazione React di grandi dimensioni è composta da molti componenti, metodi di utilità e librerie di terze parti. Se non viene fatto alcuno sforzo per provare a caricare diverse parti di un'applicazione solo quando sono necessarie, un singolo e grande bundle di JavaScript verrà inviato agli utenti non appena caricano la prima pagina. Ciò può influire notevolmente sul rendimento della pagina.

La funzione React.lazy fornisce un modo integrato per separare i componenti di un'applicazione in blocchi distinti di JavaScript con pochissimo lavoro. Puoi poi occuparti del caricamento degli stati quando lo accoppiate al componente Suspense.

Thriller

Il problema dell'invio agli utenti di un payload JavaScript di grandi dimensioni è la durata del caricamento della pagina, soprattutto su dispositivi e connessioni di rete meno potenti. Ecco perché la suddivisione del codice e il caricamento lento sono estremamente utili.

Tuttavia, gli utenti dovranno sempre attendere un leggero ritardo quando viene recuperato un componente con suddivisione del codice sulla rete, pertanto è importante visualizzare uno stato di caricamento utile. L'utilizzo di React.lazy con il componente Suspense contribuisce a risolvere il 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 accetta un componente fallback che ti consente di visualizzare qualsiasi componente React come stato di caricamento. L'esempio seguente mostra come funziona. L'avatar viene visualizzato solo quando si fa clic sul pulsante, quando viene quindi effettuata una richiesta per recuperare il codice necessario per AvatarComponent sospeso. Nel frattempo, viene mostrato il componente di caricamento di riserva.

Qui, il codice che compone AvatarComponent è piccolo, motivo per cui la rotellina di caricamento viene visualizzata solo per poco tempo. I componenti più grandi possono richiedere molto più tempo per il caricamento, soprattutto su connessioni di rete deboli.

Per dimostrare meglio come funziona:

  • Per visualizzare l'anteprima del sito, premi Visualizza app. Quindi premi A schermo intero schermo intero.
  • Premi "Control+Maiusc+J" (o "Comando+Opzione+J" su Mac) per aprire DevTools.
  • Fai clic sulla scheda Rete.
  • Fai clic sul menu a discesa Limitazione, che per impostazione predefinita è impostato su Nessuna limitazione. Seleziona 3G veloce.
  • Fai clic sul pulsante Fai clic qui nell'app.

L'indicatore di caricamento verrà visualizzato per più tempo. Tieni presente che tutto il codice che compone AvatarComponent viene recuperato come un chunk separato.

Riquadro della rete di DevTools che mostra il download di un file chunk.js

Sospensione di più componenti

Un'altra funzionalità di Suspense è che ti consente di sospendere il caricamento di più componenti, anche se sono tutti caricati in modo lazy.

Ad esempio:

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>
)

Si tratta di un modo estremamente utile per ritardare il rendering di più componenti mostrando solo un singolo stato di caricamento. Una volta completato il recupero di tutti i componenti, l'utente può visualizzarli contemporaneamente.

Puoi visualizzarlo con il seguente codice di incorporamento:

In caso contrario, è facile riscontrare il problema del caricamento frazionato, ovvero il caricamento di parti diverse di un'interfaccia utente una dopo l'altra, ognuna con il proprio indicatore di caricamento. Ciò può rendere l'esperienza utente più spiacevole.

Gestire gli errori di caricamento

Suspense ti consente di visualizzare uno stato di caricamento temporaneo mentre vengono effettuate richieste di rete sotto il cofano. Ma cosa succede se queste richieste di rete non vanno a buon fine per qualche motivo? Potresti essere offline o la tua app web sta tentando di eseguire il caricamento lazy di un URL con versione non aggiornato e non più disponibile dopo il ricollocamento del server.

React ha uno schema standard per gestire in modo elegante questi tipi di errori di caricamento: l'utilizzo di un confine di errore. Come descritto nella documentazione, qualsiasi componente React può fungere da confine di errore se implementa uno (o entrambi) dei metodi di ciclo di vita static getDerivedStateFromError() o componentDidCatch().

Per rilevare e gestire gli errori di caricamento differito, puoi racchiudere il componente Suspense con un componente principale che funge da confine di errore. All'interno del metodo render() del confine di errore, puoi visualizzare gli elementi secondari così come sono se non si verificano errori oppure visualizzare un messaggio di errore personalizzato in caso di problemi:

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>
)

Conclusione

Se non sai da dove iniziare ad applicare la suddivisione del codice alla tua applicazione React, segui questi passaggi:

  1. Inizia a livello di percorso. I percorsi sono il modo più semplice per identificare i punti della tua applicazione che possono essere suddivisi. La documentazione di React mostra come utilizzare Suspense insieme a react-router.
  2. Identifica eventuali componenti di grandi dimensioni in una pagina del tuo sito che vengono visualizzati solo in seguito a determinate interazioni dell'utente (ad esempio il clic su un pulsante). La suddivisione di questi componenti ridurrà al minimo i payload JavaScript.
  3. Valuta la possibilità di suddividere tutto ciò che non è sullo schermo e non è fondamentale per l'utente.