Skip to Content
BootstrapPartie 11 — Bootstrap avec React & Next.js11.1 — Pourquoi le JS natif casse en React/SSR

11.1 — Pourquoi le JS natif casse en React/SSR

⏱️ TL;DR — Le JS de Bootstrap manipule le DOM directement (classes, attributs, écouteurs attachés au chargement). React contrôle le DOM via son virtual DOM ; en SSR (Next.js), le HTML est d’abord rendu côté serveur où document/window n’existent pas. Résultat : data-attributes non initialisés, document is not defined, désynchronisation état/DOM. La solution : react-bootstrap ou une initialisation JS soigneuse dans useEffect.

🎯 Objectifs

  • Comprendre les trois sources de conflit.
  • Éviter les erreurs document is not defined.
  • Savoir quand useEffect suffit.

Les trois conflits

  1. DOM impératif vs virtual DOM : Bootstrap ajoute/retire des classes (show, collapse) que React ne « connaît » pas — au prochain re-render, React peut écraser ces changements.
  2. Initialisation au chargement : la Data API attache ses écouteurs une fois, au DOMContentLoaded. Les composants React montés après ne sont pas pris en compte.
  3. SSR : côté serveur, import 'bootstrap' qui touche window/document lève document is not defined.

L’erreur classique en Next.js

// ❌ dans un composant serveur (App Router) : plante au build import 'bootstrap/dist/js/bootstrap.bundle' // touche window

Initialisation correcte dans un composant client

'use client' import { useEffect, useRef } from 'react' export function InfoTooltip({ title, children }) { const ref = useRef(null) useEffect(() => { let instance // import dynamique : chargé seulement côté client import('bootstrap/js/dist/tooltip').then(({ default: Tooltip }) => { instance = new Tooltip(ref.current, { title }) }) return () => instance?.dispose() // cleanup obligatoire }, [title]) return <span ref={ref} data-bs-toggle="tooltip">{children}</span> }

Points clés : 'use client', import dynamique (évite le SSR), instanciation dans useEffect, dispose() au cleanup.

Pourquoi c’est fragile

Même bien fait, vous re-synchronisez à la main l’état React et le DOM Bootstrap. Pour un dropdown ou une modale (focus trap, fermeture au clic extérieur), c’est beaucoup de code fragile — d’où l’existence de react-bootstrap.

⚠️ Piège — Oublier le dispose() au cleanup crée des fuites mémoire et des instances fantômes quand le composant se démonte/remonte (navigation SPA). Toujours nettoyer dans le return du useEffect.

💡 Pour un dev React — Règle simple : CSS de Bootstrap = OK partout ; JS de Bootstrap = seulement en composant client, avec import dynamique + dispose, ou mieux, react-bootstrap. Ne jamais importer le JS dans un composant serveur.

✏️ Exercices

  1. Pourquoi import 'bootstrap' plante-t-il dans un composant serveur Next.js ?

✅ Solution

Le JS touche window/document, absents côté serveur → document is not defined.

  1. Que faut-il faire au démontage d’un composant qui a instancié un tooltip ?

✅ Solution

Appeler .dispose() dans le cleanup du useEffect.

🧠 Quiz de révision

1. Pourquoi le JS Bootstrap entre-t-il en conflit avec React ?

Il manipule le DOM directement, alors que React le contrôle via le virtual DOM.

2. Quelle erreur typique en SSR ?

document is not defined.

3. Où initialiser un composant JS Bootstrap en React ?

Dans un useEffect d’un composant 'use client', avec import dynamique.

4. Que faire au cleanup ?

.dispose() l’instance.

5. Le CSS de Bootstrap pose-t-il problème en SSR ?

Non — seul le JS pose problème.


Chapitre suivant : 11.2 — react-bootstrap