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

Chapitre 1 : useState

Le problème

En JavaScript classique, vous pouvez modifier une variable :

snippet.javascript
let count = 0;
count = count + 1;

Mais en React, cela ne fonctionne pas :

snippet.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 (
        <div>
            <p>{count}</p>  {/* Affiche toujours 0 */}
            <button onClick={increment}>+1</button>
        </div>
    );
}

Pourquoi ? React ne sait pas que la variable a changé. Il faut lui dire explicitement.

La solution : useState

snippet.javascript
import { useState } from 'react';
 
function Counter() {
    const [count, setCount] = useState(0);
 
    const increment = () => {
        setCount(count + 1);  // Dit à React de re-rendre
    };
 
    return (
        <div>
            <p>{count}</p>
            <button onClick={increment}>+1</button>
        </div>
    );
}

useState retourne un tableau avec :

  1. La valeur actuelle (count)
  2. Une fonction pour la modifier (setCount)

Syntaxe

snippet.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

snippet.javascript
const [count, setCount] = useState(0);
setCount(count + 1);
setCount(count - 1);

Chaînes

snippet.javascript
const [name, setName] = useState('');
setName('Jean');
setName(e.target.value);  // Pour un input

Booléens

snippet.javascript
const [isOpen, setIsOpen] = useState(false);
setIsOpen(true);
setIsOpen(!isOpen);  // Toggle

Objets

snippet.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

snippet.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 :

snippet.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

snippet.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 :

snippet.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 :

snippet.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 :

snippet.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 (
        <div>
            <button onClick={decrement} disabled={count === 0}>-</button>
            <span>{count}</span>
            <button onClick={increment} disabled={count === 10}>+</button>
        </div>
    );
}

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 :

snippet.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 (
        <div>
            <input
                value={input}
                onChange={(e) => setInput(e.target.value)}
                onKeyPress={(e) => e.key === 'Enter' && addTodo()}
            />
            <button onClick={addTodo}>Ajouter</button>
 
            <ul>
                {todos.map(todo => (
                    <li key={todo.id}>
                        {todo.text}
                        <button onClick={() => removeTodo(todo.id)}>×</button>
                    </li>
                ))}
            </ul>
        </div>
    );
}

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

← Retour au module | Chapitre suivant : useEffect →

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 1 : useState
    • Le problème
    • La solution : useState
    • Syntaxe
    • Différents types d'état
      • Nombres
      • Chaînes
      • Booléens
      • Objets
      • Tableaux
    • Mise à jour basée sur l'état précédent
    • Plusieurs états dans un composant
    • Initialisation paresseuse
    • Comparaison avec PHP
    • Exercices
      • Exercice 1 : Compteur avec min/max
      • Exercice 2 : Liste de tâches
    • 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