Maîtrisez les server et client components

Comprenez pourquoi la navigation utilise  'use client'

À la fin du chapitre précédent, nous avons ajouté  'use client'  en haut du fichier  Navigation.js  pour pouvoir utiliser  usePathname()  et afficher la route active.

Vous vous êtes peut-être demandé : pourquoi cette directive 'use client' ? C'est exactement ce que nous allons comprendre dans ce chapitre ! 

Reprenons le code de votre navigation :

'use client'

import { usePathname } from 'next/navigation'
import Link from 'next/link'
import styles from './Navigation.module.css'

export default function Navigation() {
  const pathname = usePathname()
  
  return (
    <nav className={styles.nav}>
      {/* ... */}
      <Link 
        href="/projects"
        className={pathname === '/projects' ? `${styles.link} ${styles.active}` : styles.link}
      >
        Projets
      </Link>
      {/* ... */}
    </nav>
  )
}

Que fait ce code ?

  • usePathname()récupère l'URL actuelle, par exemple/projects

  • Le composant compare l'URL avec chaque lien

Si l'URL correspond, le lien reçoit la classe active.

Découvrez les Server et Client Components

Avec React classique (Vite), tous vos composants s'exécutent dans le navigateur. Vous pouvez utiliser  useState  ,  useEffect  , et tous les hooks sans restriction.

Next.js fonctionne différemment : par défaut, vos composants sont des Server Components qui s'exécutent côté serveur !

Comprenez le principe d'un Server Component

// app/about/page.js - Server Component par défaut ✅
export default function About() {
  return (
    <div>
      <h1>À propos de moi</h1>
      <p>Développeur web passionné...</p>
    </div>
  )
}

Ce composant est rapide car :

  • Le HTML est généré côté serveur

  • Aucun JavaScript n'est envoyé au navigateur pour ce composant

  • Le contenu est immédiatement visible (SEO optimal)

Mais les Server Components ont des limitations :

  • Pas de hooks commeuseState,useEffect,usePathname

  • Pas d'événements (onClick,onChange, etc.)

  • Pas d'accès aux APIs du navigateur (window,localStorage, etc.)

Comprenez le principe d'un Client Component

Pour créer un Client Component, ajoutez  'use client'  en première ligne :

'use client'

import { useState } from 'react'

export default function Counter() {
  const [count, setCount] = useState(0)
  
  return (
    <button onClick={() => setCount(count + 1)}>
      Compteur : {count}
    </button>
  )
}

Les Client Components peuvent :

  • Utiliser tous les hooks React (useState,useEffect,usePathname, etc.)

  • Gérer les événements utilisateur (onClick,onChange, etc.)

  • Utiliser les APIs du navigateur (window,localStorage, etc.)

  • Créer de l'interactivité

Comprenez pourquoi  Navigation  est un Client Component

Revenons à notre navigation. Elle utilise  usePathname()  qui a besoin de lire l'URL dans le navigateur pour savoir quelle page est active.

'use client' // ← Nécessaire pour utiliser usePathname()

import { usePathname } from 'next/navigation'

export default function Navigation() {
  const pathname = usePathname() // ← Ce hook lit l'URL côté client
  
  // Compare l'URL avec chaque lien pour appliquer la classe active
  return (
    <Link 
      href="/projects"
      className={pathname === '/projects' ? 'active' : ''}
    >
      Projets
    </Link>
  )
}

Sans  'use client'  , vous auriez eu cette erreur :

Error: usePathname only works in Client Components

Pourquoi préférer les Server Components ?

  • Plus rapides (moins de JavaScript envoyé au navigateur)

  • Plus sécurisés (le code reste sur le serveur)

  • Meilleurs pour le SEO (HTML complet immédiatement disponible)

Quand utiliser un Client Component ?

  • Vous avez besoin de hooks (useState,useEffect,usePathname, etc.)

  • Vous gérez des événements (onClick,onChange, etc.)

  • Vous utilisez les APIs du navigateur

Ajoutez un menu burger interactif

Améliorons votre navigation avec un vrai menu burger pour mobile qui s'ouvre et se ferme au clic !

Modifiez  app/components/Navigation/Navigation.js  :

'use client'

import { useState } from 'react'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import styles from './Navigation.module.css'

export default function Navigation() {
  const [isOpen, setIsOpen] = useState(false)
  const pathname = usePathname()

  const toggleMenu = () => {
    setIsOpen(!isOpen)
  }

  const closeMenu = () => {
    setIsOpen(false)
  }

  return (
    <nav className={styles.nav}>
      <div className={styles.container}>
        <Link href="/" className={styles.logo} onClick={closeMenu}>
          Mon Portfolio
        </Link>

        {/* Bouton burger pour mobile */}
        <button 
          className={styles.burger}
          onClick={toggleMenu}
          aria-label="Menu"
        >
          <span className={isOpen ? styles.burgerOpen : ''}></span>
          <span className={isOpen ? styles.burgerOpen : ''}></span>
          <span className={isOpen ? styles.burgerOpen : ''}></span>
        </button>

        {/* Menu /}
        <ul className={`${styles.menu} ${isOpen ? styles.menuOpen : ''}`}>
          {/* liens du menu*/}
        </ul>
      </div>
    </nav>
  )
}

Ce qui a changé :

  1. useState(false): Gère l'état ouvert/fermé du menu burger

  2. toggleMenu(): Inverse l'état (ouvert ↔ fermé)

  3. closeMenu(): Ferme le menu quand on clique sur un lien

  4. Bouton burger : Trois barres qui s'animent en croix quand le menu est ouvert

  5. Classes conditionnelles :menuOpenetburgerOpenappliquées selon l'état

Pourquoi c'est un Client Component ?

  • UtiliseuseStatepour gérer l'état du menu

  • UtiliseonClickpour réagir aux clics

  • UtiliseusePathnamepour le highlighting actif

Testez ! Réduisez la fenêtre de votre navigateur, cliquez sur l'icône burger. Le menu s'ouvre avec une animation fluide depuis la droite, et les trois barres se transforment en croix !

Comprenez les règles importantes

Règle 1 : Minimisez l'usage de  'use client'

Ne mettez 'use client' que sur les composants qui ont vraiment besoin d'interactivité.

❌ Voici un mauvais exemple :

'use client' // ❌ Pas nécessaire ici !

export default function ProjectCard({ title, description }) {
  return (
    <div>
      <h2>{title}</h2>
      <p>{description}</p>
    </div>
  )
}

Ce composant est purement visuel, pas d'interactivité → Gardez-le en Server Component !

✅ Voici un bon exemple :

// Pas de 'use client' = Server Component par défaut ✅
export default function ProjectCard({ title, description }) {
  return (
    <div>
      <h2>{title}</h2>
      <p>{description}</p>
    </div>
  )
}

Règle 2 : Isolez l'interactivité dans des sous-composants

Au lieu de rendre toute une page "client", isolez seulement la partie interactive.

❌ Mauvais exemple :

'use client' // ❌ Toute la page devient Client Component

import { useState } from 'react'

export default function Projects() {
  const [filter, setFilter] = useState('all')
  
  return (
    <div>
      <h1>Mes Projets</h1>
      {/* Beaucoup de contenu statique... */}
      
      <select onChange={(e) => setFilter(e.target.value)}>
        <option value="all">Tous</option>
        <option value="web">Web</option>
      </select>
      
      {/* Plus de contenu statique... */}
    </div>
  )
}

Ici, tout le contenu statique devient Client Component alors que seul le  <select>  a besoin d'interactivité.

✅ Bon exemple :

// projects/page.js - Server Component ✅
import ProjectFilter from './ProjectFilter'

export default function Projects() {
  return (
    <div>
      <h1>Mes Projets</h1>
      {/* Contenu statique reste Server Component */}
      
      <ProjectFilter /> {/* Seul ce composant est Client */}
      
      {/* Plus de contenu statique Server Component */}
    </div>
  )
}

// ProjectFilter.js - Client Component
'use client'

import { useState } from 'react'

export default function ProjectFilter() {
  const [filter, setFilter] = useState('all')
  
  return (
    <select onChange={(e) => setFilter(e.target.value)}>
      <option value="all">Tous</option>
      <option value="web">Web</option>
    </select>
  )
}

Avantages :

  • Moins de JavaScript envoyé au navigateur

  • Meilleure performance

  • Meilleur SEO (le contenu statique reste en Server Component)

Règle 3 : Un Client Component peut importer un Server Component

✅ Bon exemple :

'use client'

import { useState } from 'react'

export default function ClientParent({ children }) {
  const [count, setCount] = useState(0)
  
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>+</button>
      {children} {/* ✅ Le Server Component est passé en children */}
    </div>
  )
}

// page.js
import ClientParent from './ClientParent'
import ServerChild from './ServerChild' // Server Component

export default function Page() {
  return (
    <ClientParent>
      <ServerChild /> {/* ✅ Fonctionne ! */}
    </ClientParent>
  )
}

À vous de jouer !

Avant de passer au chapitre suivant, entraînez-vous :

Consigne

Pour l’instant votre formulaire n’est pas vraiment utile. Utilisez vos connaissances de React et des composants clients pour rendre le formulaire interactif.

Solution 

Dans la solution d’exemple nous avons creé un composant  ContactForm.js  pour extraire la logique client du formulaire.

Pourquoi  ContactForm  est un Client Component ?

  • Il utilise useState pour gérer les données du formulaire et le statut

  • Gère les événementsonChange et onSubmit

  • A un affichage conditionnel basé sur l'état

Testez : Remplissez le formulaire et envoyez-le. Un message de confirmation s'affiche pendant l'envoi, puis un message de succès apparaît !

Félicitations ! Vous maîtrisez maintenant les bases des Server et Client Components de Next.js.

En résumé

  • Les Server Components, par défaut dans Next.js, s'exécutent côté serveur.

  • Les Client Components permettent l'interactivité (hooks, événements) : Ajoutez  'use client'  en première ligne.

  • Utilisez des Server Components par défaut, ne passez en Client Component que si nécessaire.

  • Isolez l'interactivité dans des sous-composants, minimisez l'usage de 'use client' et gardez le maximum de contenu en Server Components.

  • Voici les Hooks que nous avons utilisés :useStategère l'état local ;useEffectgère les effets de bord (scroll, événements, localStorage) ;usePathnamedétècte de la route active.

Dans le prochain chapitre nous verrons comment récupérer et afficher des données dynamiques dans votre portfolio avec le data fetching !

Ever considered an OpenClassrooms diploma?
  • Up to 100% of your training program funded
  • Flexible start date
  • Career-focused projects
  • Individual mentoring
Find the training program and funding option that suits you best