React - Rendering and Virtual DOM

React follows a declarative approach to rendering components, which means you specify what a component should look like, and React takes care of displaying it on the screen. This is the opposite of an imperative approach, where you would write code to manually manipulate the DOM.


The React Rendering Process

The 3 Fundamental Steps

React works like a waiter in a restaurant:

  1. Trigger - The customer places an order
  2. Render - The chef prepares the dish
  3. Commit - The waiter brings the dish
function ExempleRendu() {
  const [count, setCount] = useState(0)

  console.log('RENDER: Component being rendered')

  const handleClick = () => {
    console.log('🎯 TRIGGER: State change triggered')
    setCount(count + 1) // ← Triggers a new render
  }

  return (
    <div>
      <p>Counter: {count}</p>
      <button onClick={handleClick}>+1</button>
    </div>
  )
}

1. Trigger - When React decides to render

React renders in only 2 cases:

function QuandReactRend() {
  const [state, setState] = useState(0)

  // ✅ CASE 1: Initial render (first time)
  useEffect(() => {
    console.log('🎬 First render of the component')
  }, [])

  // ✅ CASE 2: State change
  const triggerReRender = () => {
    setState(state + 1) // ← Triggers a re-render
  }

  return (
    <div>
      <p>State: {state}</p>
      <button onClick={triggerReRender}>Change state</button>
    </div>
  )
}

2. Render - React calls your components

function ExempleRenderPur() {
  const [count, setCount] = useState(0)

  // ⚠️ This function MUST be pure!
  // Same inputs = same outputs
  console.log('🔄 Render called with count =', count)

  return <div>Count: {count}</div>
}

// ❌ BAD - Side effect during render
function BadExample() {
  const [count, setCount] = useState(0)

  // ❌ Never do this in the render!
  document.title = `Count: ${count}` // Side effect
  Math.random() // Non-deterministic

  return <div>{count}</div>
}

// ✅ GOOD - Pure render
function GoodExample() {
  const [count, setCount] = useState(0)

  // ✅ Side effects in useEffect
  useEffect(() => {
    document.title = `Count: ${count}`
  }, [count])

  return <div>{count}</div>
}

3. Commit - React updates the DOM

function ExempleCommit() {
  const [color, setColor] = useState('red')

  return (
    <div>
      {/* React will only update the color in the DOM */}
      <div style={{ backgroundColor: color, padding: '20px' }}>
        <h2>Unchanged title</h2>
        <p>Unchanged paragraph</p>
        <button onClick={() => setColor(color === 'red' ? 'blue' : 'red')}>
          Change color
        </button>
      </div>
    </div>
  )
}

Virtual DOM - The Magic of React

What is the Virtual DOM?

The Virtual DOM (VDOM) is an in-memory representation of the real DOM. It's like a draft that React uses to optimize updates.

// What you write in JSX
function MonComposant() {
  return (
    <div className="container">
      <h1>Title</h1>
      <p>Paragraph</p>
    </div>
  )
}

// What React creates in Virtual DOM (simplified)
const virtualDOM = {
  type: 'div',
  props: { className: 'container' },
  children: [
    { type: 'h1', props: {}, children: ['Title'] },
    { type: 'p', props: {}, children: ['Paragraph'] }
  ]
}

The Reconciliation Process

function ExempleReconciliation() {
  const [items, setItems] = useState(['A', 'B', 'C'])

  const ajouterItem = () => {
    setItems([...items, `Item ${Date.now()}`])
  }

  return (
    <div>
      <h2>List of items</h2>
      {/*
        React compares:
        - BEFORE: ['A', 'B', 'C']
        - AFTER: ['A', 'B', 'C', 'Item 12345']

        Result: React ONLY adds the new element to the DOM
      */}
      <ul>
        {items.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
      <button onClick={ajouterItem}>Add item</button>
    </div>
  )
}

Why is it important?

// Without Virtual DOM (direct manipulation)
function updateWithoutVDOM() {
  // ❌ Slow and inefficient
  document.getElementById('title').textContent = 'New title'
  document.getElementById('count').textContent = '42'
  document.getElementById('status').className = 'active'
  // ... 50 other updates
}

// With Virtual DOM (React)
function updateWithVDOM() {
  // ✅ React automatically calculates the minimal changes
  setTitle('New title')
  setCount(42)
  setStatus('active')
  // React updates ONLY what has changed
}

Practical demonstration

function DemoVirtualDOM() {
  const [highlightIndex, setHighlightIndex] = useState(0)

  useEffect(() => {
    const interval = setInterval(() => {
      setHighlightIndex(prev => (prev + 1) % 5)
    }, 1000)

    return () => clearInterval(interval)
  }, [])

  return (
    <div>
      <h3>React updates ONLY the highlighted element</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>👆 Open the DevTools and look: only the color changes in the DOM!</p>
    </div>
  )
}

Resources for further learning