# 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
```javascript
import { useRef } from 'react';
function SearchForm() {
const inputRef = useRef(null);
const handleClick = () => {
inputRef.current.focus();
};
return (
);
}
```
### 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 ``
### Exemple : Scroll vers un élément
```javascript
function ScrollToSection() {
const sectionRef = useRef(null);
const scrollToSection = () => {
sectionRef.current.scrollIntoView({ behavior: 'smooth' });
};
return (
);
}
```
### Exemple : Éviter les re-exécutions de useEffect
```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 :
```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 (
);
}
```
**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
```javascript
// INCORRECT
function BadComponent() {
const ref = useRef(0);
ref.current += 1; // Modification pendant le rendu
return
{ref.current}
;
}
// 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
...
;
}
```
## 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 :**
```javascript
function LoginForm() {
const emailRef = useRef(null);
useEffect(() => {
emailRef.current.focus();
}, []);
return (
);
}
```
### Exercice 2 : Chronomètre avec pause
Créer un chronomètre avec boutons Start/Pause/Reset.
**Solution :**
```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 (
{time} secondes
);
}
```
## 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`
[[:15_training:module3-hooks-fondamentaux:useeffect|← Chapitre précédent]] | [[:15_training:module3-hooks-fondamentaux:start|Retour au module]] | [[:15_training:module3-hooks-fondamentaux:usecontext|Chapitre suivant : useContext →]]