[PARTE 2] Next.js 13: Estratégias de renderização com Pages Router vs App Router
Essa é a segunda parte da explicação, se você ainda não leu a parte 1 é leitura obrigatória para o pleno entedimento.
App Router
A primeira grande mudança em relação ao Pages Router é que agora não temos mais o conceito de páginas. Enquanto no Pages Router páginas são “componentes especiais” que podem exportar funções como getServerSideProps
, getStaticProps
, etc. e componentes são as partes que compõem essas páginas, essas funções deixam de existir e no App Router tudo são componentes. Dito isto, precisamos ter em mente que existem dois tipos de componentes:
- Client Components: O componente é pré-renderizado no lado do servidor e enviado para ser hidratado no lado do cliente.
- Server Components: O componente é pré-renderizado e hidratado no lado do servidor, enviando um componente totalmente renderizado que não requer nenhum processamento no lado do cliente.
É importante que você entenda que Client Components funcionam essencialmente como páginas funcionam no Pages Router, isto quer dizer que independente da estratégia de renderização que uma página usa ela sempre vai ser pré-renderizada no lado do servidor e hidratada no lado do cliente, e é justamente aqui que ocorre a grande mudança implicada pelos Server Components.
Importante saber
O Server Components não é uma tecnologia desenvolvida ou exclusiva do Next.js, e sim uma tecnologia desenvolvida pelo time do React que foi integrada ao Next.js através da criação do App Router.
Antes de traçar um paralelo entre as estratégias de renderização é necessário entender o novo sistema de Data Fetching do App Router. Enquanto no Pages Router podemos definir as regras de revalidação de cache de uma página gerada estaticamente através da propriedade revalidate
da função getStaticProps
ou invocando a função res.revalidate('/path-to-revalidate')
, no App Router podemos simplesmente invocar a função fetch(url, options)
dentro de um Server Component e definir as regras de revalidação de cache através das propriedades options.cache
e options.next.revalidate
. A grande mudança aqui é que agora o mesmo componente pode possuir diversas requisições com regras de revalidação de cache diferentes, proporcionando muito mais granularidade em relação as páginas geradas estaticamente no Pages Router.
Outra mudança considerável foi a adição das Dynamic Functions. Como Server Components são pré-renderizados e hidratados no lado do servidor eles não tem acesso a informações do lado do cliente como cookies, headers e parâmetros de url. Para isso foram adicionadas "funções especiais" chamadas de Dynamic Functions que conseguem acessar essas informações.
Tendo tudo isso em mente, vamos agora traçar um paralelo entre as estratégias de renderização do Pages Router e do App Router:
- SSG → Static Rendering: O HTML é pré-renderizado e hidratado no lado do servidor como um Server Component durante o processo de build, o resultado é salvo em uma CDN, enviado e exibido no lado do cliente. Um componente usa esta estratégia quando:
- Não invoca a função
fetch
. - Invoca uma ou mais funções
fetch
com a propriedadeoptions.cache: 'force-cache'
(Padrão). - Invoca uma ou mais funções
fetch
com a propriedadeoptions.next.revalidate: false
. - Não invoca uma Dynamic Function.
- Não é uma Dynamic Route.
- Exporta a variável
dynamic
com um valor diferente de'force-dynamic'
. - Exporta a variável
revalidate: false
(Padrão).
- Não invoca a função
- ISR → Static Data Fetching: O HTML é pré-renderizado e hidratado no lado do servidor como um Server Component durante o processo de build de acordo com as regras de revalidação de cache, o resultado é salvo em uma CDN, enviado e exibido no lado do cliente. Um componente usa esta estratégia quando:
- Invoca uma ou mais funções
fetch
com a propriedadeoptions.next.revalidate
com um valor maior que0
. - Não invoca uma Dynamic Function.
- Exporta a variável
dynamic
com um valor diferente de'force-dynamic'
. - É uma Dynamic Route, exporta a função
generateStaticParams
e exporta a variáveldynamicParams: true
(Padrão). - Exporta a variável
revalidate
com um valor maior que0
. - Invoca a função
revalidatePath
. - Invoca a função
revalidateTag
.
- Invoca uma ou mais funções
- SSR → Dynamic Rendering e Dynamic Data Fetching: O HTML é pré-renderizado e hidratado no lado do servidor como um Server Component a cada requisição, enviado e exibido no lado do cliente. Um componente usa estas estratégias quando:
- Invoca uma ou mais funções
fetch
com a propriedadeoptions.cache: 'no-store'
. - Invoca uma ou mais funções
fetch
com a propriedadeoptions.next.revalidate: 0
. - Invoca uma Dynamic Function.
- Exporta a variável
dynamic: 'force-dynamic'
. - Exporta a variável
revalidate: 0
.
- Invoca uma ou mais funções
- CSR → Client Components: O HTML é pré-renderizado no lado do servidor como um Client Component a cada requisição, enviado e hidratado no lado do cliente. Um componente usa esta estratégia quando:
- Possui a diretiva
use client
no topo do arquivo antes de qualquerimport
.
- Possui a diretiva
Pontos importantes
- Diferente do Pages Router em que todas as páginas são reativas, no App Router apenas Client Components são reativos, já que é a única estratégia de renderização em que o processo de hidratação acontece no lado do cliente, isto quer dizer que você não pode utilizar States, Events, Effects e APIs do navegador em Server Components, limitando-se as Dynamic Functions.
- Todas as funções e variáveis citadas no App Router são exclusivas dos Server Components, isto quer dizer que você não pode usá-las em Client Components. A busca de dados e atualização da tela em Client Components continua sendo feita no lado do cliente assim como no Pages Router, através de Effects ou utilizando bibliotecas especializadas como SWR ou TanStack Query (Recomendado).
- Exportar a variável
dynamic: 'force-dynamic'
é equivalente a invocar todas as funçõesfetch
de um componente com as propriedadesoptions.next.revalidate: 0
ouoptions.cache: 'no-store'
no App Router, ou exportar a funçãogetServerSideProps
no Pages Router. - Exportar a função
generateStaticParams
e a variáveldynamicParams
no App Router é equivalente a exportar a funçãogetStaticPaths
com a propriedadefallback
no Pages Router. - Exportar a variável
revalidate: false
(Padrão) também pode ser representado comorevalidate: 'force-cache'
. - A variável
fetchCache
não está sendo considerado aqui, pois é recomendado evitar utilizá-la já que ela sobrepõe o comportamento padrão de revalidação de cache.
Sinta-se a vontade para fazer críticas, sugestões ou tirar dúvidas nos comentários. Vlw!!!
Otimo post, aqui tem uma otima referencia sobre react server components e client components:
https://nextjs.org/docs/getting-started/react-essentials
Valew por compartilhar esse conteudo ;)