SmarMaker - Documentation
Docs» 15_training:module3-hooks-fondamentaux:useref

Chapitre 3 : useRef

Deux usages de useRef

useRef a deux usages principaux :

  1. Accéder à un élément DOM (input, div, etc.)
  2. Stocker une valeur qui persiste entre les rendus sans déclencher de re-rendu

Accéder au DOM

Exemple : Focus sur un input

snippet.javascript
import { useRef } from 'react';
 
function SearchForm() {
    const inputRef = useRef(null);
 
    const handleClick = () => {
        inputRef.current.focus();
    };
 
    return (
        <div>
            <input ref={inputRef} type="text" placeholder="Rechercher..." />
            <button onClick={handleClick}>Mettre le focus</button>
        </div>
    );
}

Comment ça marche

  1. useRef(null) crée un objet { current: null }
  2. ref={inputRef} dit à React de mettre l'élément DOM dans inputRef.current
  3. Après le rendu, inputRef.current contient l'élément <input>

Exemple : Scroll vers un élément

snippet.javascript
function ScrollToSection() {
    const sectionRef = useRef(null);
 
    const scrollToSection = () => {
        sectionRef.current.scrollIntoView({ behavior: 'smooth' });
    };
 
    return (
        <div>
            <button onClick={scrollToSection}>Aller à la section</button>
 
            {/* ... beaucoup de contenu ... */}
 
            <section ref={sectionRef}>
                <h2>Section cible</h2>
            </section>
        </div>
    );
}

Exemple : Mesurer un élément

snippet.javascript
function MeasuredBox() {
    const boxRef = useRef(null);
    const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
 
    useEffect(() => {
        if (boxRef.current) {
            const { width, height } = boxRef.current.getBoundingClientRect();
            setDimensions({ width, height });
        }
    }, []);
 
    return (
        <div>
            <div ref={boxRef} style={{ padding: 20, background: '#eee' }}>
                Contenu de la boîte
            </div>
            <p>Dimensions : {dimensions.width} x {dimensions.height}</p>
        </div>
    );
}

Stocker une valeur persistante

Différence avec useState

Critère useState useRef
Persiste entre rendus Oui Oui
Déclenche un re-rendu Oui Non
Accès à la valeur state ref.current

Exemple : Compter les rendus

snippet.javascript
function RenderCounter() {
    const [count, setCount] = useState(0);
    const renderCount = useRef(0);
 
    // Incrémenté à chaque rendu, sans causer de re-rendu
    renderCount.current += 1;
 
    return (
        <div>
            <p>Count : {count}</p>
            <p>Rendus : {renderCount.current}</p>
            <button onClick={() => setCount(c => c + 1)}>+1</button>
        </div>
    );
}

Exemple : Valeur précédente

snippet.javascript
function usePrevious(value) {
    const ref = useRef();
 
    useEffect(() => {
        ref.current = value;
    }, [value]);
 
    return ref.current;
}
 
function Counter() {
    const [count, setCount] = useState(0);
    const previousCount = usePrevious(count);
 
    return (
        <div>
            <p>Actuel : {count}</p>
            <p>Précédent : {previousCount}</p>
            <button onClick={() => setCount(c => c + 1)}>+1</button>
        </div>
    );
}

Exemple : Éviter les re-exécutions de useEffect

snippet.javascript
function Timer({ onTick }) {
    const onTickRef = useRef(onTick);
 
    // Met à jour la ref sans déclencher de re-rendu
    useEffect(() => {
        onTickRef.current = onTick;
    }, [onTick]);
 
    useEffect(() => {
        const interval = setInterval(() => {
            onTickRef.current();  // Utilise toujours la dernière version
        }, 1000);
 
        return () => clearInterval(interval);
    }, []);  // Pas besoin de onTick dans les dépendances
}

Cas d'usage avec formulaires non contrôlés

Parfois, il est plus simple de lire la valeur du DOM directement :

snippet.javascript
function UncontrolledForm() {
    const nameRef = useRef(null);
    const emailRef = useRef(null);
 
    const handleSubmit = (e) => {
        e.preventDefault();
        console.log({
            name: nameRef.current.value,
            email: emailRef.current.value
        });
    };
 
    return (
        <form onSubmit={handleSubmit}>
            <input ref={nameRef} type="text" placeholder="Nom" />
            <input ref={emailRef} type="email" placeholder="Email" />
            <button type="submit">Envoyer</button>
        </form>
    );
}

Note : les formulaires contrôlés (avec useState) sont généralement préférés car ils permettent la validation en temps réel.

Attention : ne pas lire/écrire pendant le rendu

snippet.javascript
// INCORRECT
function BadComponent() {
    const ref = useRef(0);
    ref.current += 1;  // Modification pendant le rendu
    return <div>{ref.current}</div>;
}
 
// CORRECT - modifier dans useEffect ou gestionnaire d'événement
function GoodComponent() {
    const ref = useRef(0);
 
    useEffect(() => {
        ref.current += 1;  // OK dans useEffect
    });
 
    const handleClick = () => {
        ref.current += 1;  // OK dans gestionnaire
    };
 
    return <div>...</div>;
}

Exercices

Exercice 1 : Auto-focus au montage

Créer un formulaire de login qui met automatiquement le focus sur le champ email au chargement.

Solution :

snippet.javascript
function LoginForm() {
    const emailRef = useRef(null);
 
    useEffect(() => {
        emailRef.current.focus();
    }, []);
 
    return (
        <form>
            <input ref={emailRef} type="email" placeholder="Email" />
            <input type="password" placeholder="Mot de passe" />
            <button type="submit">Connexion</button>
        </form>
    );
}

Exercice 2 : Chronomètre avec pause

Créer un chronomètre avec boutons Start/Pause/Reset.

Solution :

snippet.javascript
function Stopwatch() {
    const [time, setTime] = useState(0);
    const [isRunning, setIsRunning] = useState(false);
    const intervalRef = useRef(null);
 
    useEffect(() => {
        if (isRunning) {
            intervalRef.current = setInterval(() => {
                setTime(t => t + 1);
            }, 1000);
        }
 
        return () => {
            if (intervalRef.current) {
                clearInterval(intervalRef.current);
            }
        };
    }, [isRunning]);
 
    const start = () => setIsRunning(true);
    const pause = () => setIsRunning(false);
    const reset = () => {
        setIsRunning(false);
        setTime(0);
    };
 
    return (
        <div>
            <p>{time} secondes</p>
            <button onClick={start} disabled={isRunning}>Start</button>
            <button onClick={pause} disabled={!isRunning}>Pause</button>
            <button onClick={reset}>Reset</button>
        </div>
    );
}

Points clés à retenir

  1. useRef pour le DOM : ref={myRef} puis myRef.current
  2. useRef pour persister : stocke une valeur sans re-rendu
  3. Ne pas modifier pendant le rendu : seulement dans useEffect ou événements
  4. Valeur dans .current : ref.current et non ref

← Chapitre précédent | Retour au module | Chapitre suivant : useContext →

Previous Next

Made with ❤ by CAP-REL · SmartMaker · GNU AGPL v3+
Code source · Faire un don
SmarMaker - Documentation
Traductions de cette page:
  • Français
  • Deutsch
  • English
  • Español
  • Italiano
  • Nederlands

Table of Contents

Table des matières

  • Chapitre 3 : useRef
    • Deux usages de useRef
    • Accéder au DOM
      • Exemple : Focus sur un input
      • Comment ça marche
      • Exemple : Scroll vers un élément
      • Exemple : Mesurer un élément
    • Stocker une valeur persistante
      • Différence avec useState
      • Exemple : Compter les rendus
      • Exemple : Valeur précédente
      • Exemple : Éviter les re-exécutions de useEffect
    • Cas d'usage avec formulaires non contrôlés
    • Attention : ne pas lire/écrire pendant le rendu
    • Exercices
      • Exercice 1 : Auto-focus au montage
      • Exercice 2 : Chronomètre avec pause
    • Points clés à retenir
  • SmartAuth
  • SmartMaker - Back (PHP)
    • Mapping Dolibarr - React
  • SmartMaker - Front (React)
    • Animations de pages
    • Architecture
    • Astuces
    • Calendar
    • Composants et pages
    • Configuration du Provider
    • Debug et Logs
    • Hooks SmartCommon
    • PWA (Progressive Web App)
    • Requêtes API
    • Routage
    • SmartCommon
    • Stockage de données
    • Thèmes
    • Traductions
  • HowTo - Pas à pas - Votre première application
    • Développement PHP (back)
    • Développement React (front)
    • Première étape : Module Builder Dolibarr
    • SmartAuth
    • SmartBoot : Un "squelette" quasiment prêt à l'emploi
  • Formation SmartMaker
    • Module 1 : Fondamentaux JavaScript ES6+
      • Chapitre 1 : Variables et Scope
      • Chapitre 2 : Fonctions
      • Chapitre 3 : Programmation Asynchrone
      • Chapitre 4 : Modules ES6
    • Module 2 : Introduction à React
      • Chapitre 1 : Philosophie React
      • Chapitre 2 : JSX
      • Chapitre 3 : Composants
    • Module 3 : Hooks React Fondamentaux
      • Chapitre 1 : useState
      • Chapitre 2 : useEffect
      • Chapitre 3 : useRef
      • Chapitre 4 : useContext
    • Module 4 : React Avancé
      • Chapitre 1 : useCallback et useMemo
      • Chapitre 2 : Custom Hooks
      • Chapitre 3 : Redux et Redux Toolkit
    • Module 5 : Architecture SmartMaker
      • Chapitre 1 : Structure du projet
      • Chapitre 2 : Configuration
      • Chapitre 3 : Flux de données
    • Module 6 : SmartCommon - Composants
      • Chapitre 1 : Mise en page
      • Chapitre 2 : Navigation
      • Chapitre 3 : Formulaires
      • Chapitre 4 : Affichage
    • Module 7 : SmartCommon - Hooks
      • Chapitre 1 : useApi
      • Chapitre 2 : Gestion d'état
      • Chapitre 3 : Hooks utilitaires
    • Module 8 : Backend API (PHP)
      • Chapitre 1 : Routage
      • Chapitre 2 : Controllers
      • Chapitre 3 : Mappers
      • Extrafields et formulaires dynamiques
    • Module 9 : Intégration complète
      • Chapitre 1 : Backend
      • Chapitre 2 : Frontend
      • Chapitre 3 : Déploiement
    • Module 10 : Fonctionnalités avancées
      • Chapitre 1 : Mode offline
      • Chapitre 2 : Internationalisation (i18n)
      • Chapitre 3 : Autres fonctionnalités
    • Module 11 : Bonnes pratiques
  • Démonstration
  • Start
  • Composants et pages
  • Afficher le texte source
  • Anciennes révisions
  • Liens de retour
  • Haut de page