# Chapitre 1 : useState ## Le problème En JavaScript classique, vous pouvez modifier une variable : ```javascript let count = 0; count = count + 1; ``` Mais en React, cela ne fonctionne pas : ```javascript function Counter() { let count = 0; const increment = () => { count = count + 1; // La variable change... console.log(count); // Affiche bien 1, 2, 3... }; // Mais l'UI n'est JAMAIS mise à jour ! return (

{count}

{/* Affiche toujours 0 */}
); } ``` **Pourquoi ?** React ne sait pas que la variable a changé. Il faut lui dire explicitement. ## La solution : useState ```javascript import { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); const increment = () => { setCount(count + 1); // Dit à React de re-rendre }; return (

{count}

); } ``` `useState` retourne un tableau avec : 1. **La valeur actuelle** (`count`) 2. **Une fonction pour la modifier** (`setCount`) ## Syntaxe ```javascript const [state, setState] = useState(initialValue); ``` - `state` : la valeur actuelle - `setState` : fonction pour modifier la valeur - `initialValue` : valeur initiale (une seule fois au premier rendu) ## Différents types d'état ### Nombres ```javascript const [count, setCount] = useState(0); setCount(count + 1); setCount(count - 1); ``` ### Chaînes ```javascript const [name, setName] = useState(''); setName('Jean'); setName(e.target.value); // Pour un input ``` ### Booléens ```javascript const [isOpen, setIsOpen] = useState(false); setIsOpen(true); setIsOpen(!isOpen); // Toggle ``` ### Objets ```javascript const [user, setUser] = useState({ name: '', email: '' }); // INCORRECT - mutation directe user.name = 'Jean'; // Ne fonctionne pas ! // CORRECT - nouvel objet avec spread setUser({ ...user, name: 'Jean' }); ``` ### Tableaux ```javascript const [items, setItems] = useState([]); // Ajouter un élément setItems([...items, newItem]); // Supprimer un élément setItems(items.filter(item => item.id !== idToRemove)); // Modifier un élément setItems(items.map(item => item.id === idToUpdate ? { ...item, name: 'Nouveau nom' } : item )); ``` ## Mise à jour basée sur l'état précédent Quand la nouvelle valeur dépend de l'ancienne, utilisez la forme fonctionnelle : ```javascript // PROBLÈME POTENTIEL avec plusieurs appels rapides setCount(count + 1); setCount(count + 1); // count est toujours l'ancienne valeur ! // Résultat : +1 au lieu de +2 // CORRECT - forme fonctionnelle setCount(prevCount => prevCount + 1); setCount(prevCount => prevCount + 1); // Résultat : +2 ``` La forme fonctionnelle garantit que vous travaillez avec la dernière valeur. ## Plusieurs états dans un composant ```javascript function LoginForm() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); // ... } ``` Ou regroupés dans un objet : ```javascript function LoginForm() { const [form, setForm] = useState({ email: '', password: '', isLoading: false, error: null }); const updateField = (field, value) => { setForm(prev => ({ ...prev, [field]: value })); }; // updateField('email', 'jean@example.com'); } ``` ## Initialisation paresseuse Si la valeur initiale nécessite un calcul coûteux, passez une fonction : ```javascript // PROBLÈME - calcul exécuté à chaque rendu const [data, setData] = useState(expensiveCalculation()); // CORRECT - calcul exécuté une seule fois const [data, setData] = useState(() => expensiveCalculation()); ``` ## Comparaison avec PHP ^ Concept ^ PHP (session) ^ React (useState) ^ | Stockage | `$_SESSION['count'] = 0` | `useState(0)` | | Lecture | `$_SESSION['count']` | `count` | | Écriture | `$_SESSION['count']++` | `setCount(c => c + 1)` | | Persistance | Côté serveur | Mémoire navigateur | ## Exercices ### Exercice 1 : Compteur avec min/max Créer un compteur qui : - Ne peut pas descendre en dessous de 0 - Ne peut pas dépasser 10 **Solution :** ```javascript function Counter() { const [count, setCount] = useState(0); const increment = () => { setCount(prev => Math.min(prev + 1, 10)); }; const decrement = () => { setCount(prev => Math.max(prev - 1, 0)); }; return (
{count}
); } ``` ### Exercice 2 : Liste de tâches Créer un composant qui : - Affiche une liste de tâches - Permet d'ajouter une tâche - Permet de supprimer une tâche **Solution :** ```javascript function TodoList() { const [todos, setTodos] = useState([]); const [input, setInput] = useState(''); const addTodo = () => { if (input.trim()) { setTodos([...todos, { id: Date.now(), text: input }]); setInput(''); } }; const removeTodo = (id) => { setTodos(todos.filter(todo => todo.id !== id)); }; return (
setInput(e.target.value)} onKeyPress={(e) => e.key === 'Enter' && addTodo()} />
); } ``` ## Points clés à retenir 1. **useState** retourne `[valeur, setValeur]` 2. **Ne jamais modifier** l'état directement, toujours utiliser le setter 3. **Spread operator** pour les objets et tableaux : `{...obj}`, `[...arr]` 4. **Forme fonctionnelle** : `setState(prev => ...)` quand le nouvel état dépend de l'ancien 5. L'état est **local** au composant [[:15_training:module3-hooks-fondamentaux:start|← Retour au module]] | [[:15_training:module3-hooks-fondamentaux:useeffect|Chapitre suivant : useEffect →]]