Você nunca precisa enviar mais código do que o necessário para os usuários. Portanto, divida seus pacotes para garantir que isso nunca aconteça.
O método React.lazy
facilita a divisão de código de um aplicativo React em um
nível de componente usando importações dinâmicas.
import React, { lazy } from 'react';
const AvatarComponent = lazy(() => import('./AvatarComponent'));
const DetailsComponent = () => (
<div>
<AvatarComponent />
</div>
)
Por que isso é útil?
Um aplicativo React grande geralmente consiste em muitos componentes, métodos de utilitários e bibliotecas de terceiros. Se não for feito um esforço para carregar diferentes partes de um aplicativo somente quando elas forem necessárias, um único pacote grande de JavaScript será enviado aos usuários assim que eles carregarem a primeira página. Isso pode afetar significativamente a performance da página.
A função React.lazy
oferece uma maneira integrada de separar componentes de um
aplicativo em partes separadas de JavaScript com muito pouco trabalho. Em seguida,
você pode cuidar dos estados de carregamento ao combiná-lo com o componente
Suspense
.
Suspense
O problema de enviar um payload grande de JavaScript para os usuários é o tempo que a página leva para terminar o carregamento, especialmente em dispositivos mais fracos e conexões de rede. É por isso que a divisão de código e o carregamento lento são extremamente úteis.
No entanto, sempre haverá um pequeno atraso quando os usuários
buscarem um componente de divisão de código pela rede. Por isso, é importante
exibir um estado de carregamento útil. Usar React.lazy
com o componente Suspense
ajuda a resolver esse 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
aceita um componente fallback
, que permite exibir qualquer componente
do React como um estado de carregamento. O exemplo a seguir mostra como isso funciona.
O avatar só é renderizado quando o botão é clicado, quando uma solicitação é
feita para recuperar o código necessário para o AvatarComponent
suspenso.
Enquanto isso, o componente de carregamento substituto é mostrado.
Aqui, o código que compõe AvatarComponent
é pequeno, e é
por isso que o ícone de carregamento aparece apenas por um curto período. Componentes
maiores podem levar mais tempo para carregar, especialmente em
conexões de rede fracas.
Para demonstrar melhor como isso funciona:
- Para visualizar o site, pressione View App. Em seguida, pressione Fullscreen .
- Pressione "Control+Shift+J" (ou "Command+Option+J" no Mac) para abrir as Ferramentas do desenvolvedor.
- Clique na guia Rede.
- Clique no menu suspenso Limitação, que é definido como Sem limitação por padrão. Selecione 3G rápido.
- Clique no botão Click Me no app.
O indicador de carregamento vai aparecer por mais tempo. Observe como todo o código que
compõe o AvatarComponent
é buscado como um fragmento separado.
Suspensão de vários componentes
Outro recurso do Suspense
é que ele permite suspender o carregamento de vários
componentes, mesmo que todos sejam carregados de forma lazy.
Exemplo:
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>
)
Essa é uma maneira extremamente útil de atrasar a renderização de vários componentes, mostrando apenas um único estado de carregamento. Quando todos os componentes terminarem a busca, o usuário poderá ver todos eles exibidos ao mesmo tempo.
Confira isso com a seguinte incorporação:
Sem isso, é fácil encontrar o problema de carregamento escalonado ou diferentes partes de uma interface de carregamento uma após a outra, cada uma com seu próprio indicador de carregamento. Isso pode tornar a experiência do usuário mais desagradável.
Processar falhas de carregamento
Suspense
permite mostrar um estado de carregamento temporário enquanto as solicitações
de rede são feitas em segundo plano. Mas e se essas solicitações de rede falharem por algum motivo? Talvez você esteja off-line ou seu app da Web esteja tentando
carregar com carregamento lento um URL com versão
que está desatualizado e não está mais disponível após uma nova implantação do servidor.
O React tem um padrão padrão para lidar com esses tipos de falhas
de carregamento: usando um limite de erro. Conforme descrito na documentação,
qualquer componente do React pode servir como um limite de erro se implementar um (ou
ambos) dos métodos de ciclo de vida static getDerivedStateFromError()
ou
componentDidCatch()
.
Para detectar e processar falhas de carregamento lento, você pode agrupar o componente Suspense
com um componente pai que serve como um limite de erro. Dentro do
método render()
do limite de erro, é possível renderizar os filhos como estão se não houver
erro ou renderizar uma mensagem de erro personalizada se algo der errado:
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>
)
Conclusão
Se você não souber por onde começar a aplicar a divisão de código no seu aplicativo React, siga estas etapas:
- Comece no nível da rota. As rotas são a maneira mais simples de identificar pontos
do aplicativo que podem ser divididos. Os
documentos do React
mostram como
Suspense
pode ser usado comreact-router
. - Identifique componentes grandes em uma página do seu site que são renderizados apenas em determinadas interações do usuário (como clicar em um botão). A divisão desses componentes vai minimizar seus payloads JavaScript.
- Considere dividir tudo o que estiver fora da tela e não for essencial para o usuário.