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
getStaticPropscomrevalidate: false, ou não é uma Dynamic Route. - ISR: Página exporta
getStaticPropscomrevalidatemaior que 0 e/ou invocares.revalidate(‘/path-to-revalidate’)e é uma Dynamic Route. - SSR: Página exporta
getServerSidePropsougetInitialProps(Legado). - CSR: Página não exporta
getServerSideProps,getInitialProps(Legado), ougetStaticProps.
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 comoptions.next.revalidate: 0ouoptions.cache: 'no-store'no App Router. - A variável
fetchCachenã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: 0para 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
dynamicforça a renderização dinâmica para todos os componentes.