Il problema: un sito che non sfrutta l'App Router
Hai un sito Next.js con il vecchio pages router. Ogni pagina si ricarica completamente. I loading spinner appaiono a caso. Un errore in un componente blocca l'intera schermata. E per organizzare le route devi creare cartelle con nomi improbabili.
Noi, di Meteora Web, abbiamo visto decine di progetti così. Siti che avrebbero potuto volare ma si trascinavano per colpa di una struttura non pensata. L'App Router di Next.js risolve tutto questo. Ma va capito nel profondo, non solo letto su un tutorial astratto.
In questa guida ti spieghiamo perché layout, loading, error e route groups sono strumenti che cambiano il modo di sviluppare e come usarli subito nei tuoi progetti.
Layout: la spina dorsale della navigazione
Un layout in App Router è un componente che avvolge le pagine figlie e non si ri-renderizza quando navighi tra di esse. Questo significa che la sidebar, l'header, il footer — tutto ciò che è comune — rimane intatto. L'utente percepisce il passaggio come istantaneo.
Per creare un layout, basta un file layout.tsx (o .js) nella cartella della route. Next.js lo annida automaticamente: ogni layout avvolge i layout delle sotto-cartelle.
// app/layout.tsx — layout principale
import type { ReactNode } from 'react';
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="it">
<body>
<header>Intestazione globale</header>
<main>{children}</main>
<footer>Piè di pagina</footer>
</body>
</html>
);
}
Puoi creare layout annidati per sezioni specifiche. Ad esempio, una dashboard con sidebar e un'area admin con layout diverso.
// app/dashboard/layout.tsx
import Sidebar from '@/components/Sidebar';
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
<div className="flex">
<Sidebar />
<main>{children}</main>
</div>
);
}
Errore comune: credere che il layout si ricarichi se cambi pagina. Non è vero: Next.js mantiene lo stato del layout finché navighi all'interno della stessa gerarchia. Se hai un contatore in un layout, non si azzera.
Loading: non un semplice spinner
Il file loading.tsx è un componente che Next.js mostra istantaneamente mentre la pagina (o il segmento) sta caricando i dati. Grazie ai Server Components e allo streaming, l'utente vede subito qualcosa, anche se il contenuto principale è in arrivo.
// app/prodotti/loading.tsx
export default function Loading() {
return (
<div className="grid grid-cols-3 gap-4">
{Array.from({ length: 6 }).map((_, i) => (
<div key={i} className="h-48 bg-gray-200 animate-pulse rounded" />
))}
</div>
);
}
Il loading viene mostrato subito (prima che la pagina abbia finito di caricare) e poi sostituito automaticamente. È perfetto per pagine che fanno fetch di dati lenti (API, database).
Consiglio pratico: non creare un unico loading per tutto il sito. Metti loading diversi per ogni sezione. Così l'utente capisce subito cosa sta caricando. Un loading generico per tutto l'e-commerce è peggio di niente.
Error: isolare i fallimenti
Quando un Server Component lancia un'eccezione, tutto si blocca. Con error.tsx delimiti il problema a un segmento specifico. L'errore viene catturato e mostri un'UI di fallback, mentre il resto del sito continua a funzionare.
// app/prodotti/error.tsx
'use client';
export default function ErrorBoundary({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<div className="text-center p-8">
<h2>Qualcosa è andato storto</h2>
<p>{error.message}</p>
<button
onClick={() => reset()}
className="mt-4 bg-blue-600 text-white px-4 py-2 rounded"
>
Riprova
</button>
</div>
);
}
Il componente error.tsx deve essere un Client Component ('use client') perché ha stato e gestione eventi. Next.js lo renderizza lato client quando si verifica un errore nel Server Component padre.
Nota importante: l'errore non si propaga verso l'alto. Se metti un error.tsx in app/prodotti/error.tsx, l'errore riguarda solo /prodotti e le sue sotto-pagine. Il resto del sito (es. homepage) rimane integro.
Per errori globali (es. 404), usa il file not-found.tsx a livello di root.
Route Groups: organizzare senza intaccare l'URL
Le route groups sono cartelle il cui nome è racchiuso tra parentesi tonde (nome). Non influiscono sull'URL, ma permettono di raggruppare logicamente le route e applicare layout diversi.
app/
├── (marketing)/
│ ├── layout.tsx
│ ├── page.tsx → /
│ └── chi-siamo/page.tsx → /chi-siamo
├── (shop)/
│ ├── layout.tsx
│ ├── prodotti/page.tsx → /prodotti
│ └── carrello/page.tsx → /carrello
└── (auth)/
├── login/page.tsx → /login
└── registrazione/page.tsx → /registrazione
Ogni gruppo può avere il proprio layout, loading e error. L'URL finale è determinato dal percorso dentro il gruppo, ignorando le parentesi.
Scenario reale: un sito con sezione marketing (layout con hero e CTA) e sezione dashboard (layout con sidebar). Con i route groups non devi replicare logiche di routing complesse: crei i gruppi e assegni layout diversi.
Attenzione: non puoi avere due route groups che definiscono la stessa path. Esempio: (marketing)/chi-siamo e (shop)/chi-siamo generano conflitto perché entrambi puntano a /chi-siamo.
Mettere tutto insieme: un esempio concreto
Immagina un'applicazione di amministrazione con due sezioni: una pubblica (landing, contatti) e una privata (dashboard, utenti).
app/
├── (public)/
│ ├── layout.tsx // layout marketing
│ ├── page.tsx // homepage
│ └── contatti/page.tsx
├── (private)/
│ ├── layout.tsx // layout con sidebar
│ ├── loading.tsx // spinner per tutta la sezione privata
│ ├── error.tsx // errore globale per la sezione privata
│ ├── dashboard/page.tsx
│ └── utenti/
│ ├── page.tsx
│ ├── loading.tsx // spinner specifico per utenti
│ └── error.tsx // errore specifico per utenti
Così la sezione pubblica ha un layout leggero, mentre quella privata carica la sidebar e ha loading/error dedicati. I dati della dashboard non bloccano la navigazione tra pagine pubbliche.
Cosa fare adesso
- Migra un progetto esistente: crea un nuovo progetto Next.js con
create-next-app@lateste scegli App Router. - Identifica le sezioni comuni del tuo sito (header, footer, sidebar) e trasformale in layout.
- Aggiungi loading.tsx per ogni pagina che fa fetch di dati. Usa skeleton placeholder, non lo spinner classico.
- Metti error.tsx in ogni cartella di route che può fallire (elenchi, dettagli, form).
- Riorganizza le cartelle con route groups per separare aree con layout diversi (pubblico, privato, amministrazione).
- Testa il comportamento: naviga tra pagine e controlla che i layout non si ricarichino e che errori siano isolati.
Se vuoi approfondire, consulta la documentazione ufficiale di Next.js sul routing. E ricorda: un'applicazione ben strutturata non è un lusso, è la differenza tra un sito che vende e uno che frustra gli utenti.
Sponsored Protocol