Next.js transforme React en une suite complète d'outils pour le développement web moderne. Sa dernière version apporte des fonctionnalités révolutionnaires qui changent notre façon de construire des applications web. Découvrons pourquoi Next.js est devenu incontournable !
Les points forts de Next.js 15 🎯
- App Router - Un système de routage moderne basé sur le système de fichiers
- Server Components - Composants React rendus côté serveur par défaut
- Server Actions - Mutations serveur directement depuis vos composants
- Streaming - Chargement progressif des pages pour une UX fluide
- Cache intelligent - Mise en cache automatique des données
- Zero config - Prêt à l'emploi avec des optimisations intégrées
Démarrage rapide ⚙️
1# Création d'un nouveau projet
2npx create-next-app@latest mon-app --typescript --tailwind --app
3
4# Lancement du serveur de développement
5cd mon-app
6npm run dev
Architecture moderne 📂
L'App Router introduit une nouvelle structure de projet plus intuitive :
1mon-app/
2├── app/
3│ ├── layout.tsx # Layout racine
4│ ├── page.tsx # Page d'accueil (/)
5│ ├── loading.tsx # Chargement global
6│ ├── error.tsx # Gestion d'erreur
7│ ├── not-found.tsx # Page 404
8│ ├── blog/
9│ │ ├── page.tsx # /blog
10│ │ └── [slug]/
11│ │ └── page.tsx # /blog/:slug
12│ └── api/
13│ └── route.ts # API Routes
14├── components/
15│ ├── server/ # Components serveur
16│ ├── client/ # Components client
17│ └── ui/ # UI components
18└── lib/
19 └── actions.ts # Server Actions
Server Components ⚡️
Les composants sont rendus côté serveur par défaut pour de meilleures performances :
1// app/blog/page.tsx
2import { PostList } from '@/components/server/PostList';
3import { Suspense } from 'react';
4
5export default async function BlogPage() {
6 return (
7 <main className="container mx-auto px-4 py-8">
8 <h1 className="text-4xl font-bold mb-8">Notre Blog</h1>
9 <Suspense fallback={<p>Chargement des articles...</p>}>
10 <PostList />
11 </Suspense>
12 </main>
13 );
14}
15
16// components/server/PostList.tsx
17async function getPosts() {
18 const posts = await db.post.findMany();
19 return posts;
20}
21
22export async function PostList() {
23 const posts = await getPosts();
24
25 return (
26 <div className="grid gap-6 md:grid-cols-2">
27 {posts.map(post => (
28 <article key={post.id} className="p-4 rounded-lg border">
29 <h2 className="text-xl font-semibold">{post.title}</h2>
30 <p className="mt-2 text-gray-600">{post.excerpt}</p>
31 </article>
32 ))}
33 </div>
34 );
35}
Client Components 🔄
Pour les composants nécessitant de l'interactivité :
1// components/client/SearchBar.tsx
2'use client';
3
4import { useState } from 'react';
5import { useRouter } from 'next/navigation';
6
7export function SearchBar() {
8 const [query, setQuery] = useState('');
9 const router = useRouter();
10
11 function handleSearch(e: React.FormEvent) {
12 e.preventDefault();
13 router.push(`/search?q=${encodeURIComponent(query)}`);
14 }
15
16 return (
17 <form onSubmit={handleSearch} className="flex gap-2">
18 <input
19 type="search"
20 value={query}
21 onChange={(e) => setQuery(e.target.value)}
22 placeholder="Rechercher..."
23 className="px-4 py-2 rounded border"
24 />
25 <button type="submit" className="px-4 py-2 bg-blue-500 text-white rounded">
26 Rechercher
27 </button>
28 </form>
29 );
30}
Server Actions ⚡️
Mutations côté serveur directement depuis vos composants :
1// lib/actions.ts
2'use server';
3
4import { revalidatePath } from 'next/cache';
5import { redirect } from 'next/navigation';
6import { z } from 'zod';
7
8const PostSchema = z.object({
9 title: z.string().min(3, "Le titre doit contenir au moins 3 caractères"),
10 content: z.string().min(10, "Le contenu doit contenir au moins 10 caractères")
11});
12
13export async function createPost(formData: FormData) {
14 const data = {
15 title: formData.get('title'),
16 content: formData.get('content')
17 };
18
19 const result = PostSchema.safeParse(data);
20
21 if (!result.success) {
22 return { error: result.error.flatten() };
23 }
24
25 const post = await db.post.create({
26 data: result.data
27 });
28
29 revalidatePath('/blog');
30 redirect('/blog');
31}
32
33// app/blog/new/page.tsx
34import { createPost } from '@/lib/actions';
35
36export default function NewPostPage() {
37 return (
38 <form action={createPost} className="space-y-4 max-w-lg mx-auto">
39 <div>
40 <label htmlFor="title" className="block text-sm font-medium">
41 Titre
42 </label>
43 <input
44 type="text"
45 name="title"
46 id="title"
47 required
48 className="mt-1 block w-full rounded-md border-gray-300"
49 />
50 </div>
51 <div>
52 <label htmlFor="content" className="block text-sm font-medium">
53 Contenu
54 </label>
55 <textarea
56 name="content"
57 id="content"
58 required
59 rows={5}
60 className="mt-1 block w-full rounded-md border-gray-300"
61 />
62 </div>
63 <button
64 type="submit"
65 className="w-full py-2 px-4 bg-blue-500 text-white rounded-md"
66 >
67 Publier
68 </button>
69 </form>
70 );
71}
Routes API modernes 🛠️
1// app/api/posts/route.ts
2import { NextResponse } from 'next/server';
3import { z } from 'zod';
4
5const PostSchema = z.object({
6 title: z.string().min(3),
7 content: z.string().min(10),
8});
9
10export async function GET(request: Request) {
11 const { searchParams } = new URL(request.url);
12 const query = searchParams.get('q');
13
14 const posts = await db.post.findMany({
15 where: query
16 ? {
17 OR: [
18 { title: { contains: query } },
19 { content: { contains: query } },
20 ],
21 }
22 : undefined,
23 });
24
25 return NextResponse.json({ posts });
26}
27
28export async function POST(request: Request) {
29 try {
30 const body = await request.json();
31 const result = PostSchema.safeParse(body);
32
33 if (!result.success) {
34 return NextResponse.json(
35 { error: result.error.flatten() },
36 { status: 400 },
37 );
38 }
39
40 const post = await db.post.create({
41 data: result.data,
42 });
43
44 return NextResponse.json(post, { status: 201 });
45 } catch (error) {
46 return NextResponse.json({ error: 'Erreur serveur' }, { status: 500 });
47 }
48}
Optimisations et bonnes pratiques 🚀
1. Streaming avec Suspense
1import { Suspense } from 'react';
2import { PostList } from '@/components/server/PostList';
3import { SidebarNav } from '@/components/server/SidebarNav';
4import { Loading } from '@/components/ui/Loading';
5
6export default function BlogLayout({
7 children
8}: {
9 children: React.ReactNode
10}) {
11 return (
12 <div className="flex gap-8">
13 <Suspense fallback={<Loading />}>
14 <SidebarNav />
15 </Suspense>
16 <main className="flex-1">
17 <Suspense fallback={<Loading />}>
18 {children}
19 </Suspense>
20 </main>
21 <aside className="w-64">
22 <Suspense fallback={<Loading />}>
23 <PostList type="recent" />
24 </Suspense>
25 </aside>
26 </div>
27 );
28}
2. Gestion des erreurs
1// app/error.tsx
2'use client';
3
4export default function Error({
5 error,
6 reset
7}: {
8 error: Error & { digest?: string };
9 reset: () => void;
10}) {
11 return (
12 <div className="flex flex-col items-center justify-center min-h-[400px]">
13 <h2 className="text-2xl font-bold mb-4">
14 Une erreur est survenue !
15 </h2>
16 <button
17 onClick={() => reset()}
18 className="px-4 py-2 bg-blue-500 text-white rounded"
19 >
20 Réessayer
21 </button>
22 </div>
23 );
24}
3. Chargement optimisé des images
1import Image from 'next/image';
2
3export function Avatar({ src, alt }: { src: string; alt: string }) {
4 return (
5 <div className="relative w-10 h-10">
6 <Image
7 src={src}
8 alt={alt}
9 fill
10 sizes="40px"
11 className="rounded-full object-cover"
12 priority
13 />
14 </div>
15 );
16}
Pour aller plus loin 🎈
En résumé ✨
Next.js 15 représente une évolution majeure dans le développement web React avec :
- Server-first : Composants serveur par défaut pour de meilleures performances
- Simplicité : Une architecture intuitive basée sur les fichiers
- Performance : Optimisations automatiques et streaming
- DX améliorée : Server Actions et API Routes modernes
La combinaison du App Router, des Server Components et des Server Actions offre une base solide pour construire des applications web modernes, performantes et maintenables.
Maintenant que tu comprends les bases de Next.js 14, tu es prêt à créer des applications web modernes et performantes ! N'hésite pas à consulter la documentation officielle pour approfondir chaque concept. Bon développement ! 🚀