React - Rendu et Virtual DOM
React suit une approche déclarative pour le rendu des composants, ce qui signifie que tu spécifies ce à quoi un composant doit ressembler, et React s'occupe de l'afficher à l'écran. C'est l'opposé d'une approche impérative, où tu écrirais du code pour manipuler manuellement le DOM.
Le Processus de Rendu React
Les 3 étapes fondamentales
React fonctionne comme un serveur dans un restaurant :
- Trigger (Déclenchement) - Le client passe commande
- Render (Rendu) - Le chef prépare le plat
- Commit (Validation) - Le serveur apporte le plat
function ExempleRendu() {
const [count, setCount] = useState(0)
console.log('RENDER: Composant en cours de rendu')
const handleClick = () => {
console.log('🎯 TRIGGER: Changement d\'état déclenché')
setCount(count + 1) // ← Déclenche un nouveau rendu
}
return (
<div>
<p>Compteur: {count}</p>
<button onClick={handleClick}>+1</button>
</div>
)
}
1. Trigger - Quand React décide de faire un rendu
React fait un rendu dans 2 cas seulement :
function QuandReactRend() {
const [state, setState] = useState(0)
// ✅ CAS 1: Rendu initial (première fois)
useEffect(() => {
console.log('🎬 Premier rendu du composant')
}, [])
// ✅ CAS 2: Changement d'état
const triggerReRender = () => {
setState(state + 1) // ← Déclenche un re-rendu
}
return (
<div>
<p>State: {state}</p>
<button onClick={triggerReRender}>Changer état</button>
</div>
)
}
2. Render - React appelle tes composants
function ExempleRenderPur() {
const [count, setCount] = useState(0)
// ⚠️ Cette fonction DOIT être pure !
// Mêmes inputs = mêmes outputs
console.log('🔄 Render appelé avec count =', count)
return <div>Count: {count}</div>
}
// ❌ MAUVAIS - Effet de bord pendant le render
function BadExample() {
const [count, setCount] = useState(0)
// ❌ Ne jamais faire ça dans le render !
document.title = `Count: ${count}` // Effet de bord
Math.random() // Non-déterministe
return <div>{count}</div>
}
// ✅ BON - Render pur
function GoodExample() {
const [count, setCount] = useState(0)
// ✅ Effets de bord dans useEffect
useEffect(() => {
document.title = `Count: ${count}`
}, [count])
return <div>{count}</div>
}
3. Commit - React met à jour le DOM
function ExempleCommit() {
const [color, setColor] = useState('red')
return (
<div>
{/* React ne mettra à jour QUE la couleur dans le DOM */}
<div style={{ backgroundColor: color, padding: '20px' }}>
<h2>Titre inchangé</h2>
<p>Paragraphe inchangé</p>
<button onClick={() => setColor(color === 'red' ? 'blue' : 'red')}>
Changer couleur
</button>
</div>
</div>
)
}
Virtual DOM - La Magie de React
Qu'est-ce que le Virtual DOM ?
Le Virtual DOM (VDOM) est une représentation en mémoire du DOM réel. C'est comme un brouillon que React utilise pour optimiser les mises à jour.
// Ce que tu écris en JSX
function MonComposant() {
return (
<div className="container">
<h1>Titre</h1>
<p>Paragraphe</p>
</div>
)
}
// Ce que React crée en Virtual DOM (simplifié)
const virtualDOM = {
type: 'div',
props: { className: 'container' },
children: [
{ type: 'h1', props: {}, children: ['Titre'] },
{ type: 'p', props: {}, children: ['Paragraphe'] }
]
}
Le Processus de Réconciliation
function ExempleReconciliation() {
const [items, setItems] = useState(['A', 'B', 'C'])
const ajouterItem = () => {
setItems([...items, `Item ${Date.now()}`])
}
return (
<div>
<h2>Liste d'items</h2>
{/*
React compare :
- AVANT: ['A', 'B', 'C']
- APRÈS: ['A', 'B', 'C', 'Item 12345']
Résultat: React ajoute SEULEMENT le nouvel élément au DOM
*/}
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
<button onClick={ajouterItem}>Ajouter item</button>
</div>
)
}
Pourquoi c'est important ?
// Sans Virtual DOM (manipulation directe)
function updateWithoutVDOM() {
// ❌ Lent et inefficace
document.getElementById('title').textContent = 'Nouveau titre'
document.getElementById('count').textContent = '42'
document.getElementById('status').className = 'active'
// ... 50 autres mises à jour
}
// Avec Virtual DOM (React)
function updateWithVDOM() {
// ✅ React calcule automatiquement les changements minimaux
setTitle('Nouveau titre')
setCount(42)
setStatus('active')
// React met à jour SEULEMENT ce qui a changé
}
Démonstration pratique
function DemoVirtualDOM() {
const [highlightIndex, setHighlightIndex] = useState(0)
useEffect(() => {
const interval = setInterval(() => {
setHighlightIndex(prev => (prev + 1) % 5)
}, 1000)
return () => clearInterval(interval)
}, [])
return (
<div>
<h3>React met à jour SEULEMENT l'élément surligné</h3>
<ul>
{['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5'].map((item, index) => (
<li
key={index}
style={{
backgroundColor: index === highlightIndex ? 'yellow' : 'transparent',
padding: '10px',
transition: 'background-color 0.3s'
}}
>
{item}
</li>
))}
</ul>
<p>👆 Ouvre les DevTools et regarde: seule la couleur change dans le DOM !</p>
</div>
)
}