Skip to main content

Page router e App Router

  • Page router e App Router

Nivelando o conhecimento

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

Conceitos Fundamentais

Antes de prosseguir, vamos relembrar alguns conceitos essenciais para um entendimento pleno das estratégias de renderização. Quando falamos de React e Next.js, deparamo-nos frequentemente com os termos:

  • Renderização (Rendering): É o processo pelo qual o React converte o código em HTML, permitindo que o navegador "desenhe a interface" na tela.
  • Pré-renderização (Pre-rendering): É o processo pelo qual o Next.js converte o código em HTML no lado do servidor.
  • Hidratação (Hydration): É o processo pelo qual o React "injeta" os valores do JSON e as instruções JavaScript no HTML renderizado, tornando a página interativa.

Estratégias de Renderização no Next.js

  • SSG (Static Site Generation): O HTML é pré-renderizado no lado do servidor durante o processo de build e salvo em uma CDN. A página é enviada e hidratada no lado do cliente.
  • ISR (Incremental Static Regeneration): O HTML é pré-renderizado no lado do servidor de acordo com as regras de revalidação de cache. A página é salva em uma CDN, enviada e hidratada no lado do cliente.
  • SSR (Server-side Rendering): O HTML é pré-renderizado no lado do servidor a cada requisição e enviado para o lado do cliente.
  • CSR (Client-side Rendering): O HTML é pré-renderizado no lado do servidor a cada requisição e enviado para o lado do cliente. A página busca os dados necessários e atualiza a tela no lado do cliente.

Estratégias de Renderização Disponíveis em Cada Router

Pages Router

  • SSG: Página sem função exportada, ou exporta getStaticProps com revalidate: false, ou não é uma Dynamic Route.
  • ISR: Página exporta getStaticProps com revalidate maior que 0 e/ou invoca res.revalidate(‘/path-to-revalidate’) e é uma Dynamic Route.
  • SSR: Página exporta getServerSideProps ou getInitialProps (Legado).
  • CSR: Página não exporta getServerSidePropsgetInitialProps (Legado), ou getStaticProps.

App Router

  • Static Rendering: Componente é pré-renderizado no lado do servidor como Server Component durante o build.
  • Static Data Fetching: Componente é pré-renderizado no lado do servidor como Server Component de acordo com as regras de revalidação de cache.
  • Dynamic Rendering e Dynamic Data Fetching: Componente é pré-renderizado no lado do servidor como Server Component a cada requisição.

Pontos Importantes

  • Diferente do Pages Router, no App Router, apenas Client Components são reativos.
  • Todas as funções e variáveis citadas no App Router são exclusivas dos Server Components.
  • Exportar a variável dynamic: 'force-dynamic' é equivalente a invocar todas as funções fetch de um componente com options.next.revalidate: 0 ou options.cache: 'no-store' no App Router.
  • A variável fetchCache não está sendo considerada aqui, pois é recomendado evitar utilizá-la.

Exemplos

Pages Router

Static Site Generation (SSG)

// pages/index.js
export default function Home({ posts }) {
return (
<div>
{posts.map((post) => (
<div key={post.id}>{post.title}</div>
))}
</div>
);
}

export async function getStaticProps() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
const posts = await res.json();

return {
props: {
posts,
},
};
}
  • A página é pré-renderizada no build.

Incremental Static Regeneration (ISR)

// pages/blog/[id].js
export default function BlogPost({ post }) {
return (
<div>
<h1>{post.title}</h1>
<p>{post.body}</p>
</div>
);
}

export async function getStaticPaths() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
const posts = await res.json();

const paths = posts.map((post) => ({
params: { id: post.id.toString() },
}));

return { paths, fallback: 'blocking' };
}

export async function getStaticProps({ params }) {
const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${params.id}`);
const post = await res.json();

return {
props: {
post,
},
revalidate: 10, // Revalida a cada 10 segundos
};
}
  • A página é revalidada após 10 segundos.

Server-side Rendering (SSR)

// pages/profile.js
export default function Profile({ user }) {
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}

export async function getServerSideProps() {
const res = await fetch('https://jsonplaceholder.typicode.com/users/1');
const user = await res.json();

return {
props: {
user,
},
};
}
  • A página é renderizada a cada requisição.

Client-side Rendering (CSR)

// pages/dashboard.js
import { useEffect, useState } from 'react';

export default function Dashboard() {
const [data, setData] = useState(null);

useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then((response) => response.json())
.then((data) => setData(data));
}, []);

if (!data) return <div>Loading...</div>;

return (
<div>
<h1>{data.title}</h1>
</div>
);
}
  • A página busca dados no cliente após carregar.

App Router

Static Rendering

// app/page.js
export default function Home({ posts }) {
return (
<div>
{posts.map((post) => (
<div key={post.id}>{post.title}</div>
))}
</div>
);
}

export async function getStaticProps() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
const posts = await res.json();

return {
props: {
posts,
},
};
}
  • Similar ao SSG, mas com componentes do App Router.

Static Data Fetching

// app/page.js
export default function Home({ posts }) {
return (
<div>
{posts.map((post) => (
<div key={post.id}>{post.title}</div>
))}
</div>
);
}

export async function getStaticProps() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
const posts = await res.json();

return {
props: {
posts,
},
revalidate: 10, // Similar ao ISR
};
}

Dynamic Rendering e Dynamic Data Fetching

// app/page.js
export default async function Home() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts', {
next: { revalidate: 0 }, // Força a renderização dinâmica
});
const posts = await res.json();

return (
<div>
{posts.map((post) => (
<div key={post.id}>{post.title}</div>
))}
</div>
);
}
  • Utiliza options.next.revalidate: 0 para renderização dinâmica.

Server Actions

Server Actions permitem que você execute funções específicas no servidor. Exemplo:

// app/page.js
export default function Page() {
async function fetchData() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
return res.json();
}

const data = fetchData();

return (
<div>
{data.map((post) => (
<div key={post.id}>{post.title}</div>
))}
</div>
);
}

Dynamic

Utilizando dynamic para renderização dinâmica:

// app/page.js
export const dynamic = 'force-dynamic';

export default function Page() {
async function fetchData() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
return res.json();
}

const data = fetchData();

return (
<div>
{data.map((post) => (
<div key={post.id}>{post.title}</div>
))}
</div>
);
}
  • A variável dynamic força a renderização dinâmica para todos os componentes.