Entenda o Next.js 13! Pages Router vs App Router
Tags: nextjs, react, tutorial, braziliandevs
Published: 2023-09-21 03:51:31

## Nivelando o conhecimento

Se você esta chegando agora ao mundo do Next.js - ou ainda não entendeu o App Router - é muito importante saber o funcionamento e as diferenças entre o App Router e o Pages Router, e para isso é crucial entendermos as estratégias de renderização e como elas são “representadas” em cada Router.

Antes de prosseguir precisamos relembrar alguns conceitos para um entendimento pleno das estratégias de renderização. Quando falamos de React e Next.js diversas vezes nos deparamos com os termos renderização ([rendering](https://nextjs.org/learn/foundations/how-nextjs-works/rendering)), pré-renderização ([pre-rendering](https://nextjs.org/learn/basics/data-fetching/pre-rendering)) e hidratação ([hydration](https://react.dev/reference/react-dom/hydrate)):

- **Renderização**: É o processo que o React realiza para converter o código em HTML, tornando assim possível que o navegador consiga "desenhar a interface" na tela.

- **Pré-renderização**: É o processo que o Next.js realiza para converter o código em HTML, porém, executa este processo no lado do servidor.

- **Hidratação**: É o processo que o React realiza para "injetar" os valores do JSON e as instruções JavaScript no HTML renderizado, tornando assim a página interativa.

Você pode entender renderização e pré-renderização como o mesmo processo, sendo "pré-renderização" uma nomenclatura adotada pelo Next.js. Em resumo, enquanto o React só tem a capacidade de executar a renderização no lado do cliente, o Next.js executa este mesmo processo no lado do servidor, deixando a cargo do lado do cliente apenas a hidratação.

Ao adotar essa estratégia o Next.js oferece duas grandes vantagens em relação a um projeto "React puro" criado utilizando o [Create React App](https://create-react-app.dev/):

1. Melhor performance, pois uma parte do processamento para "criar a página" é realizado no lado do servidor.
2. Melhor experiência para o usuário, pois ao invés de exibir uma "tela branca" enquanto a página é renderizada no lado do cliente, é imediatamente exibido o HTML pré-renderizado no lado servidor, fazendo com que o lado do cliente tenha apenas que aguardar o processo de hidratação para que a página se torne interativa. É interessante ressaltar que ao desativar o JavaScript do navegador o HTML continua sendo exibido, fazendo com que apenas a parte interativa não funcione.

> **Importante saber**
> 
> Uma página gerada estaticamente e salva em uma [CDN](https://www.cloudflare.com/pt-br/learning/cdn/what-is-a-cdn/) significa que quando requisitada já possui seu HTML pré-renderizado salvo em um storage e apenas precisa enviá-lo para o cliente, não necessitando nenhum processamento no lado do servidor para pré-renderizar a página.

Entendidos esses conceitos, vamos falar sobre as estratégias de renderização disponíveis em cada Router do Next.js!

## Pages Router

- [Static Site Generation (SSG)](https://nextjs.org/docs/pages/building-your-application/rendering/static-site-generation): O HTML é pré-renderizado no lado do servidor durante o processo de build, o resultado é salvo em uma CDN, enviado e hidratado no lado do cliente. Uma página usa esta estratégia quando:
  - Não exporta nenhuma função.
  - Exporta a função [`getStaticProps`](https://nextjs.org/docs/pages/api-reference/functions/get-static-props) com a propriedade [`revalidate: false` (Padrão)](https://nextjs.org/docs/pages/api-reference/functions/get-static-props#revalidate).
  - Não é uma [Dynamic Route](https://nextjs.org/docs/pages/building-your-application/routing/dynamic-routes).
- [Incremental Static Regeneration (ISR)](https://nextjs.org/docs/pages/building-your-application/rendering/incremental-static-regeneration): O HTML é pré-renderizado no lado do servidor durante o processo de build de acordo com as regras de revalidação de cache estabelecidas, o resultado é salvo em uma CDN, enviado e hidratado no lado do cliente. Uma página usa esta estratégia quando:
  - Exporta a função [`getStaticProps` ](https://nextjs.org/docs/pages/api-reference/functions/get-static-props) com a propriedade [`revalidate`](https://nextjs.org/docs/pages/api-reference/functions/get-static-props#revalidate) com o valor maior que `0`.
  - Invoca a função [`res.revalidate(‘/path-to-revalidate’)`](https://nextjs.org/docs/pages/building-your-application/rendering/incremental-static-regeneration#on-demand-revalidation).
  - É uma [Dynamic Route](https://nextjs.org/docs/pages/building-your-application/routing/dynamic-routes) e exporta as funções [`getStaticProps` ](https://nextjs.org/docs/pages/api-reference/functions/get-static-props) e [`getStaticPaths`](https://nextjs.org/docs/pages/api-reference/functions/get-static-paths).
- [Server-side Rendering (SSR)](https://nextjs.org/docs/pages/building-your-application/rendering/server-side-rendering): O HTML é pré-renderizado no lado do servidor a cada requisição, enviado e hidratado no lado do cliente. Uma página usa esta estratégia quando:
  - Exporta a função [`getServerSideProps`](https://nextjs.org/docs/pages/api-reference/functions/get-server-side-props).
  - Exporta a função [`getInitialProps` (Legado)](https://nextjs.org/docs/pages/api-reference/functions/get-initial-props).
- [Client-side Rendering (CSR)](https://nextjs.org/docs/pages/building-your-application/rendering/client-side-rendering): O HTML é pré-renderizado no lado do servidor a cada requisição, enviado e hidratado no lado do cliente. Uma página usa esta estratégia quando:
  - Não exporta as funções [`getServerSideProps`](https://nextjs.org/docs/pages/api-reference/functions/get-server-side-props), [`getInitialProps` (Legado)](https://nextjs.org/docs/pages/api-reference/functions/get-initial-props) ou [`getStaticProps`](https://nextjs.org/docs/pages/api-reference/functions/get-static-props).
  - Busca os dados necessário e atualiza a tela no lado do cliente através de [Effects](https://react.dev/learn/synchronizing-with-effects#fetching-data) ou utilizando bibliotecas especializadas como [SWR](https://swr.vercel.app/) ou [TanStack Query](https://tanstack.com/query/v3/) (Recomendado).

### Pontos importantes

- Independente da estratégia utilizada todas as páginas são reativas, já que o processo de hidratação sempre acontece no lado do cliente, isto quer dizer que você pode utilizar [States](https://react.dev/learn/state-a-components-memory), [Events](https://react.dev/learn/responding-to-events), [Effects](https://react.dev/learn/synchronizing-with-effects) e [APIs do navegador](https://developer.mozilla.org/en-US/docs/Web/API).
- Quando uma página gerada estaticamente é requisitada mas ainda não foi gerada, não necessariamente retornará uma página de `Not Found`, sendo possível gerá-la pela primeira vez definindo a propriedade `fallback` da função [`getStaticPaths`](https://nextjs.org/docs/pages/api-reference/functions/get-static-paths) para [`true`](https://nextjs.org/docs/pages/api-reference/functions/get-static-paths#fallback-true) ou [`'blocking'`](https://nextjs.org/docs/pages/api-reference/functions/get-static-paths#fallback-blocking).

## 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`](https://nextjs.org/docs/pages/api-reference/functions/get-server-side-props), [`getStaticProps` ](https://nextjs.org/docs/pages/api-reference/functions/get-static-props), 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](https://nextjs.org/docs/getting-started/react-essentials#client-components): O componente é pré-renderizado no lado do servidor e enviado para ser hidratado no lado do cliente.
- [Server Components](https://nextjs.org/docs/getting-started/react-essentials#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](https://nextjs.org/docs/getting-started/react-essentials#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](https://nextjs.org/docs/getting-started/react-essentials#server-components).

>**Importante saber**
>
>O [Server Components](https://nextjs.org/docs/getting-started/react-essentials#server-components) não é uma tecnologia desenvolvida ou exclusiva do Next.js, e sim uma tecnologia [desenvolvida pelo time do React](https://react.dev/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components) 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](https://nextjs.org/docs/app/building-your-application/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` ](https://nextjs.org/docs/pages/api-reference/functions/get-static-props) ou invocando a função [`res.revalidate('/path-to-revalidate')`](https://nextjs.org/docs/pages/building-your-application/rendering/incremental-static-regeneration#on-demand-revalidation), no App Router podemos simplesmente invocar a função [`fetch(url, options)`](https://nextjs.org/docs/app/api-reference/functions/fetch) dentro de um [Server Component](https://nextjs.org/docs/getting-started/react-essentials#server-components) e definir as regras de revalidação de cache através das propriedades [`options.cache`](https://nextjs.org/docs/app/api-reference/functions/fetch#optionscache) e [`options.next.revalidate`](https://nextjs.org/docs/app/api-reference/functions/fetch#optionsnextrevalidate). 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](https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic-rendering#dynamic-functions). Como [Server Components](https://nextjs.org/docs/getting-started/react-essentials#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](https://nextjs.org/docs/app/api-reference/functions/cookies), [headers](https://nextjs.org/docs/app/api-reference/functions/headers) e [parâmetros de url](https://nextjs.org/docs/app/api-reference/functions/use-search-params). Para isso foram adicionadas "funções especiais" chamadas de [Dynamic Functions](https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic-rendering#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](https://nextjs.org/docs/pages/building-your-application/rendering/static-site-generation) → [Static Rendering](https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic-rendering#static-rendering-default): O HTML é pré-renderizado e hidratado no lado do servidor como um [Server Component](https://nextjs.org/docs/getting-started/react-essentials#server-components) 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`](https://nextjs.org/docs/app/api-reference/functions/fetch).
    - Invoca uma ou mais funções [`fetch`](https://nextjs.org/docs/app/api-reference/functions/fetch) com a propriedade [`options.cache: 'force-cache'` (Padrão)](https://nextjs.org/docs/app/api-reference/functions/fetch#optionscache).
    - Invoca uma ou mais funções [`fetch`](https://nextjs.org/docs/app/api-reference/functions/fetch) com a propriedade [`options.next.revalidate: false`](https://nextjs.org/docs/app/api-reference/functions/fetch#optionsnextrevalidate).
    - Não invoca uma [Dynamic Function](https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic-rendering#dynamic-functions).
    - Não é uma [Dynamic Route](https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes).
    - Exporta a variável [`dynamic`](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamic) com um valor diferente de `'force-dynamic'`.
    - Exporta a variável [`revalidate: false` (Padrão)](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#revalidate).
- [ISR](https://nextjs.org/docs/pages/building-your-application/rendering/incremental-static-regeneration) → [Static Data Fetching](https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic-rendering#static-data-fetching-default): O HTML é pré-renderizado e hidratado no lado do servidor como um [Server Component](https://nextjs.org/docs/getting-started/react-essentials#server-components) 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`](https://nextjs.org/docs/app/api-reference/functions/fetch) com a propriedade [`options.next.revalidate`](https://nextjs.org/docs/app/api-reference/functions/fetch#optionsnextrevalidate) com um valor maior que `0`.
    - Não invoca uma [Dynamic Function](https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic-rendering#dynamic-functions).
    - Exporta a variável [`dynamic`](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamic) com um valor diferente de `'force-dynamic'`.
    - É uma [Dynamic Route](https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes), exporta a função [`generateStaticParams`](https://nextjs.org/docs/app/api-reference/functions/generate-static-params) e exporta a variável [`dynamicParams: true` (Padrão)](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamicparams).
    - Exporta a variável [`revalidate`](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#revalidate) com um valor maior que `0`.
    - Invoca a função [`revalidatePath`](https://nextjs.org/docs/app/api-reference/functions/revalidatePath).
    - Invoca a função [`revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag).
- [SSR](https://nextjs.org/docs/pages/building-your-application/rendering/server-side-rendering) → [Dynamic Rendering](https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic-rendering#dynamic-rendering) e [Dynamic Data Fetching](https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic-rendering#dynamic-data-fetching): O HTML é pré-renderizado e hidratado no lado do servidor como um [Server Component](https://nextjs.org/docs/getting-started/react-essentials#server-components) 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`](https://nextjs.org/docs/app/api-reference/functions/fetch) com a propriedade [`options.cache: 'no-store'`](https://nextjs.org/docs/app/api-reference/functions/fetch#optionscache).
    - Invoca uma ou mais funções [`fetch`](https://nextjs.org/docs/app/api-reference/functions/fetch) com a propriedade [`options.next.revalidate: 0`](https://nextjs.org/docs/app/api-reference/functions/fetch#optionsnextrevalidate).
    - Invoca uma [Dynamic Function](https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic-rendering#dynamic-functions).
    - Exporta a variável [`dynamic: 'force-dynamic'`](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamic).
    - Exporta a variável [`revalidate: 0`](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#revalidate).
- [CSR](https://nextjs.org/docs/pages/building-your-application/rendering/client-side-rendering) → [Client Components](https://nextjs.org/docs/getting-started/react-essentials#client-components): O HTML é pré-renderizado no lado do servidor como um [Client Component](https://nextjs.org/docs/getting-started/react-essentials#client-components) a cada requisição, enviado e hidratado no lado do cliente. Um componente usa esta estratégia quando:
    - Possui a diretiva [`use client`](https://nextjs.org/docs/getting-started/react-essentials#the-use-client-directive) no topo do arquivo antes de qualquer `import`.
    
### Pontos importantes

- Diferente do Pages Router em que todas as páginas são reativas, no App Router apenas [Client Components](https://nextjs.org/docs/getting-started/react-essentials#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](https://react.dev/learn/state-a-components-memory), [Events](https://react.dev/learn/responding-to-events), [Effects](https://react.dev/learn/synchronizing-with-effects) e [APIs do navegador](https://developer.mozilla.org/en-US/docs/Web/API) em [Server Components](https://nextjs.org/docs/getting-started/react-essentials#server-components), limitando-se as [Dynamic Functions](https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic-rendering#dynamic-functions).
- Todas as funções e variáveis citadas no App Router são exclusivas dos [Server Components](https://nextjs.org/docs/getting-started/react-essentials#server-components), isto quer dizer que você não pode usá-las em [Client Components](https://nextjs.org/docs/getting-started/react-essentials#client-components). A busca de dados e atualização da tela em [Client Components](https://nextjs.org/docs/getting-started/react-essentials#client-components) continua sendo feita no lado do cliente assim como no Pages Router, através de [Effects](https://react.dev/learn/synchronizing-with-effects#fetching-data) ou utilizando bibliotecas especializadas como [SWR](https://swr.vercel.app/) ou [TanStack Query](https://tanstack.com/query/v3/) (Recomendado). 
- Exportar a variável [`dynamic: 'force-dynamic'`](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamic) é equivalente a invocar todas as funções [`fetch`](https://nextjs.org/docs/app/api-reference/functions/fetch) de um componente com as propriedades [`options.next.revalidate: 0`](https://nextjs.org/docs/app/api-reference/functions/fetch#optionsnextrevalidate) ou [`options.cache: 'no-store'`](https://nextjs.org/docs/app/api-reference/functions/fetch#optionscache) no App Router, ou exportar a função [`getServerSideProps`](https://nextjs.org/docs/pages/api-reference/functions/get-server-side-props) no Pages Router.    
- Exportar a função [`generateStaticParams`](https://nextjs.org/docs/app/api-reference/functions/generate-static-params) e a variável [`dynamicParams`](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#) no App Router é equivalente a exportar a função [`getStaticPaths`](https://nextjs.org/docs/pages/api-reference/functions/get-static-paths) com a propriedade `fallback` no Pages Router.
- Exportar a variável [`revalidate: false` (Padrão)](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#revalidate) também pode ser representado como [`revalidate: 'force-cache'`](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#revalidate).
- A variável [`fetchCache`](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#fetchcache) não está sendo considerado aqui pois é recomendado evitar utilizá-la, visto que ela sobrepõe o comportamento padrão de revalidação de cache.

**Críticas e sugestões são muito bem vindas, vlw!**