Articles
Sep 10, 2024

L'API Context de React : Une Solution Suffisante pour la Plupart des Besoins

La plupart du temps Redux n'est pas nécessaire et ajoute de la complexité inutile dans votre app

L'API Context de React : Une Solution Suffisante pour la Plupart des Besoins

Introduction

L'API Contexte de React est souvent un outil sous-estimé pour la gestion de l'état global des applications. Bien que des librairies comme Redux aient été largement adoptées dans la communauté React pour leur robustesse et leur flexibilité, l'API Contexte offre une solution plus simple et tout aussi efficace pour de nombreux cas d'utilisation. Dans cet article, nous allons explorer comment l'API Contexte est souvent suffisante, voire préférable, par rapport à d'autres librairies comme Redux, et nous discuterons des évolutions prévues pour cette API dans la version 19 de React.

Comprendre l'API Contexte

L'API Contexte permet de passer des données à travers l'arborescence des composants sans avoir à passer explicitement des props à chaque niveau. C'est particulièrement utile pour les données globales comme l'utilisateur authentifié, le thème de l'application, ou les paramètres de configuration.

Voici un exemple simple d'utilisation de l'API Contexte pour gérer l'état global d'une app :

import React, { createContext, useReducer, useContext } from 'react';

// Initial State
const initialState = {
  users: [],
  preferences: {
    theme: 'light',
    notifications: true,
  },
};

// Actions
const ADD_USER = 'ADD_USER';
const UPDATE_USER = 'UPDATE_USER';
const SET_THEME = 'SET_THEME';
const TOGGLE_NOTIFICATIONS = 'TOGGLE_NOTIFICATIONS';

// Reducer function
function appReducer(state, action) {
  switch (action.type) {
    case ADD_USER:
      return {
        ...state,
        users: [...state.users, action.payload],
      };
    case UPDATE_USER:
      return {
        ...state,
        users: state.users.map((user) =>
          user.id === action.payload.id ? { ...user, ...action.payload } : user
        ),
      };
    case SET_THEME:
      return {
        ...state,
        preferences: {
          ...state.preferences,
          theme: action.payload,
        },
      };
    case TOGGLE_NOTIFICATIONS:
      return {
        ...state,
        preferences: {
          ...state.preferences,
          notifications: !state.preferences.notifications,
        },
      };
    default:
      return state;
  }
}

// Create Context
const AppContext = createContext();

// Wrapper component providing the context
export function AppProvider({ children }) {
  const [state, dispatch] = useReducer(appReducer, initialState);

  // Helper functions
  const addUser = (user) => dispatch({ type: ADD_USER, payload: user });
  const setTheme = (theme) => dispatch({ type: SET_THEME, payload: theme });
  const toggleNotifications = () => dispatch({ type: TOGGLE_NOTIFICATIONS });

  return (
    <AppContext.Provider
      value={{
        state,
        addUser,
        setTheme,
        toggleNotifications,
      }}
    >
      {children}
    </AppContext.Provider>
  );
}

// Custom hook for using context
export function useAppContext() {
  return useContext(AppContext);
}

Ensuite, utilisons ce contexte pour ajouter et mettre à jour des utilisateurs et gérer les préférences utilisateur.

import React from 'react';
import { AppProvider, useAppContext } from './AppContext';

function UserList() {
  const { state } = useAppContext();
  return (
    <div>
      <h2>Users</h2>
      <ul>
        {state.users.map((user) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </div>
  );
}

function UserForm() {
  const { addUser } = useAppContext();

  const handleAddUser = () => {
    addUser({ id: 1, name: 'John Doe' });
  };

  return (
    <div>
      <button onClick={handleAddUser}>Add User</button>
    </div>
  );
}

function Preferences() {
  const { state, setTheme, toggleNotifications } = useAppContext();

  const handleToggleTheme = () => {
    setTheme(state.preferences.theme === 'light' ? 'dark' : 'light');
  };

  const handleToggleNotifications = () => {
    toggleNotifications();
  };

  return (
    <div>
      <h2>Preferences</h2>
      <button onClick={handleToggleTheme}>
        Toggle Theme (Current: {state.preferences.theme})
      </button>
      <button onClick={handleToggleNotifications}>
        Toggle Notifications (Current: {state.preferences.notifications ? 'On' : 'Off'})
      </button>
    </div>
  );
}

function App() {
  return (
    <AppProvider>
      <div>
        <h1>Application</h1>
        <UserForm />
        <UserList />
        <Preferences />
      </div>
    </AppProvider>
  );
}

export default App;

Pourquoi l'API Contexte est Suffisante pour la Plupart des Besoins

  1. Simplicité et Facilité de Mise en Place : Contrairement à Redux, qui nécessite une certaine configuration initiale et l'apprentissage de concepts comme les reducers et les actions, l'API Contexte est intuitive et rapide à mettre en place. Vous définissez simplement votre contexte, fournissez une valeur et consommez cette valeur où vous en avez besoin.
  2. Performances : Pour des applications de taille moyenne, l'API Contexte est généralement suffisante en termes de performance. Redux, bien qu'efficace, peut introduire une complexité et une surcharge de performances inutiles pour des applications plus simples.
  3. Couplage Étroit avec React : L'API Contexte est intégrée directement dans React, ce qui favorise une meilleure interopérabilité et une plus grande simplicité. Il n'y a pas besoin de se soucier de la compatibilité avec des versions spécifiques de bibliothèques tierces.
  4. Nature Descriptive : L'utilisation du Contexte dans React donne lieu à un code plus déclaratif et souvent plus lisible. Les composants restent focalisés sur le "quoi" plutôt que le "comment".

Évolutions Futures dans React 19

La version 19 de React promet quelques améliorations pour createContext, notament grâce au nouveau hook "use":

Voici par exemple ce qu'un mélange de ces deux fonctions donnerait : il suffirait uniquement de passer notre contexte à la fonction use.

import { createContext, use } from 'react';
const IngredientsContext = createContext();
function Ingredients() {
  const ingredients = use(IngredientsContext);
  return (
    <ul>
      
      {ingredients.map((ingredient) => (
        <li key={ingredient}>{ingredient}</li>
      ))}
    </ul>
  );
}
export default function App() {
  return (
    <IngredientsContext value={['Chocolat', 'Kiwi', 'Flocons']}>
      <Ingredients />{' '}
    </IngredientsContext>
  );
}

Nous n'avons pas eu besoin d'utiliser IngredientsContext.Provider. Il suffit uniquement d'utiliser notre contexte avec son nom IngredientsContext.

Conclusion

En somme, l'API Contexte de React est un outil puissant et souvent suffisant pour les besoins de la plupart des applications. Son intégration transparente avec React, sa simplicité et les améliorations continues en font une alternative viable à des solutions plus complexes comme Redux. Avec les prochaines évolutions dans la version 19, l'API Contexte continuera de gagner en efficacité et en robustesse.

Et si l'état que vous devez gérer est vraiment trop complexe solon vous pour react.context, je vous conseille l'utilisation de Zustand qui est très simple d'utilisation.