UseReducer

useReducer est un Hooks (React) de React, un outil puissant pour gérer l'état local (state) d'un composant, surtout quand cet état est complexe ou contient plusieurs sous-valeurs. C'est une alternative à useState, particulièrement adaptée quand tu as besoin de gérer des logiques d'état plus élaborées ou des transitions d'état plus prédictibles.

Fonctionnement de useReducer

useReducer te permet de décentraliser la logique de gestion de l'état dans un "reducer", une fonction qui décide comment l'état doit changer en réponse à des actions spécifiques. Cette fonction prend deux arguments : l'état actuel et une action à exécuter, puis retourne le nouvel état.

Structure de base

La signature de useReducer est la suivante :

const [state, dispatch] = useReducer(reducer, initialState);
  • reducer : C'est une fonction qui reçoit l'état actuel et une action, puis retourne le nouvel état.
  • initialState : L'état initial de ton composant.
  • state : L'état courant de ton composant, mis à jour après l'exécution des actions.
  • dispatch : Une fonction que tu appelles pour exécuter une action. Cette action est passée au reducer pour calculer le nouvel état.

Exemple pratique

Imaginons que tu développes une application pour gérer un panier d'achat. L'état du panier peut inclure des articles ajoutés, supprimés, ou mis à jour. Voici comment tu pourrais utiliser useReducer pour gérer cet état.

Définition du reducer

type State = {
    items: { id: number; name: string; quantity: number }[];
};

type Action =
    | { type: 'add'; item: { id: number; name: string; quantity: number } }
    | { type: 'remove'; id: number }
    | { type: 'increment'; id: number }
    | { type: 'decrement'; id: number };

function reducer(state: State, action: Action): State {
    switch (action.type) {
        case 'add':
            return { ...state, items: [...state.items, action.item] };
        case 'remove':
            return { ...state, items: state.items.filter(item => item.id !== action.id) };
        case 'increment':
            return {
                ...state,
                items: state.items.map(item =>
                    item.id === action.id ? { ...item, quantity: item.quantity + 1 } : item
                )
            };
        case 'decrement':
            return {
                ...state,
                items: state.items.map(item =>
                    item.id === action.id ? { ...item, quantity: Math.max(0, item.quantity - 1) } : item
                )
            };
        default:
            throw new Error('Unhandled action');
    }
}

const initialState: State = { items: [] };

Utilisation dans un composant React

const ShoppingCart: React.FC = () => {
    const [state, dispatch] = useReducer(reducer, initialState);

    return (
        <div>
            {state.items.map(item => (
                <div key={item.id}>
                    {item.name} (Quantity: {item.quantity})
                    <button onClick={() => dispatch({ type: 'increment', id: item.id })}>+</button>
                    <button onClick={() => dispatch({ type: 'decrement', id: item.id })}>-</button>
                    <button onClick={() => dispatch({ type: 'remove', id: item.id })}>Remove</button>
                </div>
            ))}
        </div>
    );
};

Ce code montre un panier simple où tu peux ajouter, enlever, ou ajuster la quantité des articles. Chaque action déclenche une mise à jour de l'état qui est gérée de manière prévisible par le reducer.

Pour approfondir ta compréhension de React et des concepts avancés de la programmation en général, voici une liste de notions que tu pourrais explorer :

  1. Hooks personnalisés : Création de tes propres hooks pour encapsuler la logique de composants réutilisable.

  2. Context API : Gestion du partage des données sans avoir à passer les props à travers plusieurs niveaux d'arborescence de composants.

  3. Optimisation des performances dans React :

  4. React Router : Gestion des routes dans tes applications React pour naviguer entre différents composants ou pages.

  5. Gestion d'état avancée :

    • Redux pour la gestion d'état centralisée.
    • Recoil ou Zustand, des bibliothèques modernes de gestion d'état.
  6. Test de composants React :

    • Jest pour les tests unitaires.
    • React Testing Library pour tester les composants en imitant leur usage dans le navigateur.
  7. Server-Side Rendering : Techniques pour rendre des applications React côté serveur avec Next.js par exemple, pour améliorer le chargement initial des pages et le SEO.

  8. react-suspense et Lazy Loading : Techniques pour diviser le code et charger les composants de manière paresseuse pour améliorer les performances de l'application.

  9. Webhooks et l'intégration avec des services externes : Comment intégrer et utiliser des webhooks pour réagir à des événements externes dans tes applications React.

Chacune de ces notions peut ouvrir de nouvelles portes dans ta façon de développer et d'architecturer tes applications React.