Le problème avec useEffect
// ❌ Ancien pattern — waterfall, pas de cache, UX dégradée
useEffect(() => {
fetch('/api/projects')
.then(r => r.json())
.then(setProjects);
}, []);Ce code souffre de plusieurs problèmes : la requête part *après* le premier rendu côté client, créant un flash de contenu vide. Le cache HTTP est ignoré. Et en mode Strict, il s'exécute deux fois en dev.
La solution : Server Components
Avec les React Server Components, le fetch se fait directement dans le composant, côté serveur, avant l'envoi du HTML au client :
// ✅ Server Component — zéro waterfall, cache natif
export default async function ProjectsPage() {
const projects = await db.select().from(projectsTable);
return <ProjectsList projects={projects} />;
}Le rendu est bloquant (dans le bon sens) : le HTML arrive déjà rempli. Pas de skeleton, pas de flash.
Ce que j'ai appris en migrant ce portfolio
1. **Séparer les concerns** : composants serveur pour le data-fetching, composants client pour l'interactivité.
2. **Faire confiance au cache** : fetch dans les Server Components est patché par Next.js et dédupliqué automatiquement.
3. **Streaming avec Suspense** : pour les données lentes, <Suspense fallback={<Skeleton />}> est bien plus propre qu'un état loading.