Nouveau : Datasets open source gratuits disponibles !Decouvrir →
💻
Intermediaire 25 min React Hooks

Migrer de React Class vers React Hooks

Pourquoi Migrer de React Class vers React Hooks ?

La transition depuis les classes React à React Hooks est une étape cruciale pour beaucoup de développeurs JavaScript, notamment ceux qui travaillent avec des projets plus récents ou nécessitant de nouvelles fonctionnalités. Les hooks ont été introduits en 2018 et offrent une nouvelle façon de gérer le state et d'autres aspects de la logique dans les composants React. Ils sont conçus pour rendre le code plus simple, plus réutilisable et plus facile à comprendre.

Contexte réel : Pourquoi un dev a besoin de ca au quotidien ?

En raison des avantages que les hooks offrent en termes de lisibilité, de maintenabilité et de performance, de nombreux développeurs ont décidé de migrer leurs projets existants vers le modèle fonctionnel avec React Hooks. Par exemple, dans un projet de gestion de tâches, utiliser un hook comme useState pour gérer l'état des tâches et useEffect pour effectuer des opérations asynchrones permet une meilleure organisation du code et une meilleure séparation des responsabilités.

Un cas d'utilisation concret en 2-3 phrases

Imaginez que vous développez une application de notification. Chaque utilisateur peut avoir plusieurs notifications qui peuvent être marquées comme lues ou non. En utilisant les hooks, vous pouvez gérer l'état des notifications et effectuer des mises à jour asynchrones pour marquer les notifications comme lues, tout en restant dans le modèle fonctionnel de React.

Prerequis

Pour suivre ce tutoriel, vous aurez besoin des connaissances suivantes :

  • React : Connaissance avancée des concepts de base de React.
  • JavaScript ES6+ : Familiarité avec les fonctions fléchées, les promesses, etc.
  • Concepts React Fonctionnels : Comprendre les concepts comme useState, useEffect et useContext.

Les outils suivants doivent être installés sur votre système :

  • Node.js : Version recommandée est la dernière LTS (Long-Term Support) version. Vous pouvez l'installer depuis nodejs.org.
  • npm/yarn : Gestionnaire de paquets pour installer les dépendances.

Concepts fondamentaux

useState

useState est un hook qui permet de ajouter du state local dans un composant fonctionnel. Il retourne une paire: l'état actuel et une fonction à appeler pour le mettre à jour.

import React, { useState } from 'react';

function Example() {
  // Déclarez une nouvelle variable d'état qui est appelée "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Vous avez cliqué {count} fois</p>
      <button onClick={() => setCount(count + 1)}>
        Cliquez-moi
      </button>
    </div>
  );
}

useEffect

useEffect est un hook qui permet d'effectuer des effets secondaires dans les composants fonctionnels. Il peut être utilisé pour des opérations comme le chargement de données, l'abonnement à des événements, etc.

import React, { useState, useEffect } from 'react';

function Example() {
  const [data, setData] = useState(null);

  useEffect(() => {
    // Effectue un appel API pour récupérer les données
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => setData(data));
  }, []); // Le tableau vide signifie que cet effet ne sera exécuté qu'une seule fois

  return (
    <div>
      {data ? <p>{data.message}</p> : <p>Loading...</p>}
    </div>
  );
}

useContext

useContext est un hook qui permet d'accéder aux valeurs fournies par le contexte dans les composants fonctionnels. Cela simplifie la gestion du state global.

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

const ThemeContext = createContext('light');

function ThemedButton() {
  const theme = useContext(ThemeContext);

  return (
    <button style=background: theme === 'dark' ? '#000' : '#fff', color: theme === 'dark' ? '#fff' : '#000'>
      Je suis un bouton {theme}
    </button>
  );
}

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <ThemedButton />
    </ThemeContext.Provider>
  );
}

Mise en pratique : projet fil rouge

Pour illustrer la transition, nous allons créer un mini-projet simple : un gestionnaire de tâches.

Étape 1 : Création du projet

Commencez par créer un nouveau projet React :

npx create-react-app task-manager
cd task-manager

Étape 2 : Création d'un composant TaskList

Créez un fichier src/TaskList.js et ajoutez le code suivant :

import React, { useState } from 'react';

function TaskList() {
  const [tasks, setTasks] = useState([
    { id: 1, text: 'Faire les courses', completed: false },
    { id: 2, text: 'Nettoyer la maison', completed: true },
  ]);

  const toggleTaskCompletion = (id) => {
    setTasks(tasks.map(task =>
      task.id === id ? { ...task, completed: !task.completed } : task
    ));
  };

  return (
    <div>
      <h1>Gestionnaire de tâches</h1>
      <ul>
        {tasks.map(task => (
          <li key={task.id} onClick={() => toggleTaskCompletion(task.id)}>
            {task.text} - {task.completed ? 'Terminée' : 'Non terminée'}
          </li>
        ))}
      </ul>
    </div>
  );
}

export default TaskList;

Étape 3 : Utilisation du composant TaskList

Modifiez le fichier src/App.js pour utiliser le composant TaskList :

import React from 'react';
import TaskList from './TaskList';

function App() {
  return (
    <div className="App">
      <TaskList />
    </div>
  );
}

export default App;

Étape 4 : Ajout de nouvelles tâches

Pour ajouter de nouvelles tâches, nous allons modifier le composant TaskList pour inclure un formulaire :

import React, { useState } from 'react';

function TaskList() {
  const [tasks, setTasks] = useState([
    { id: 1, text: 'Faire les courses', completed: false },
    { id: 2, text: 'Nettoyer la maison', completed: true },
  ]);
  const [newTaskText, setNewTaskText] = useState('');

  const toggleTaskCompletion = (id) => {
    setTasks(tasks.map(task =>
      task.id === id ? { ...task, completed: !task.completed } : task
    ));
  };

  const addTask = () => {
    if (newTaskText.trim()) {
      setTasks([...tasks, { id: tasks.length + 1, text: newTaskText, completed: false }]);
      setNewTaskText('');
    }
  };

  return (
    <div>
      <h1>Gestionnaire de tâches</h1>
      <input
        type="text"
        value={newTaskText}
        onChange={(e) => setNewTaskText(e.target.value)}
        placeholder="Ajouter une tâche"
      />
      <button onClick={addTask}>Ajouter</button>
      <ul>
        {tasks.map(task => (
          <li key={task.id} onClick={() => toggleTaskCompletion(task.id)}>
            {task.text} - {task.completed ? 'Terminée' : 'Non terminée'}
          </li>
        ))}
      </ul>
    </div>
  );
}

export default TaskList;

Étape 5 : Suppression de tâches

Pour supprimer des tâches, nous allons ajouter un bouton de suppression :

import React, { useState } from 'react';

function TaskList() {
  const [tasks, setTasks] = useState([
    { id: 1, text: 'Faire les courses', completed: false },
    { id: 2, text: 'Nettoyer la maison', completed: true },
  ]);
  const [newTaskText, setNewTaskText] = useState('');

  const toggleTaskCompletion = (id) => {
    setTasks(tasks.map(task =>
      task.id === id ? { ...task, completed: !task.completed } : task
    ));
  };

  const addTask = () => {
    if (newTaskText.trim()) {
      setTasks([...tasks, { id: tasks.length + 1, text: newTaskText, completed: false }]);
      setNewTaskText('');
    }
  };

  const deleteTask = (id) => {
    setTasks(tasks.filter(task => task.id !== id));
  };

  return (
    <div>
      <h1>Gestionnaire de tâches</h1>
      <input
        type="text"
        value={newTaskText}
        onChange={(e) => setNewTaskText(e.target.value)}
        placeholder="Ajouter une tâche"
      />
      <button onClick={addTask}>Ajouter</button>
      <ul>
        {tasks.map(task => (
          <li key={task.id} onClick={() => toggleTaskCompletion(task.id)}>
            {task.text} - {task.completed ? 'Terminée' : 'Non terminée'}
            <button onClick={() => deleteTask(task.id)}>Supprimer</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default TaskList;

Erreurs fréquentes et debugging

Erreur 1 : TypeError: Cannot read property 'state' of undefined

Cette erreur se produit souvent lorsque vous essayez d'accéder à la propriété state sur un composant fonctionnel qui n'utilise pas les hooks de state.

## ❌ Mauvais
function Example() {
  return (
    <div>
      {this.state.count}
    </div>
  );
}

## ✅ Correct
import React, { useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  return (
    <div>
      {count}
    </div>
  );
}

Erreur 2 : Error: Maximum update depth exceeded

Cette erreur se produit lorsque vous mettez à jour le state de manière infinie. Assurez-vous que votre fonction de mise à jour ne cause pas une boucle indéfinie.

## ❌ Mauvais
import React, { useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    setCount(count + 1);
  }, []);

  return (
    <div>
      {count}
    </div>
  );
}

## ✅ Correct
import React, { useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const timer = setInterval(() => {
      setCount(prevCount => prevCount + 1);
    }, 1000);

    return () => clearInterval(timer);
  }, []);

  return (
    <div>
      {count}
    </div>
  );
}

Erreur 3 : Error: Invalid hook call. Hooks can only be called inside of the body of a function component or a custom Hook.

Cette erreur se produit lorsque vous essayez de déclarer un hook à l'extérieur d'un composant fonctionnel ou d'une fonction personnalisée.

## ❌ Mauvais
import React, { useState } from 'react';

const [count, setCount] = useState(0); // Erreur : pas dans une fonction

function Example() {
  return (
    <div>
      {count}
    </div>
  );
}

## ✅ Correct
import React, { useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  return (
    <div>
      {count}
    </div>
  );
}

Pour aller plus loin

1. useReducer pour gérer des états complexes

Lorsque votre état devient complexe et nécessite beaucoup de logique, vous pouvez utiliser useReducer. C'est une alternative à useState qui est souvent plus utile dans ces cas.

Documentation officielle

2. useCallback pour optimiser les performances

En utilisant useCallback, vous pouvez éviter la création de fonctions dépendantes du rendu, ce qui améliore les performances en évitant les re-rendus inutiles.

Documentation officielle

3. useMemo pour stocker des valeurs mises en cache

Lorsque vous avez besoin de calculer une valeur qui est coûteuse à calculer, utilisez useMemo pour la stocker et l'utiliser à nouveau si les dépendances n'ont pas changé.

Documentation officielle

Défi pratique : Créer un mini-projet de todolist

Créez une application simple de todolist qui permet d'ajouter, de supprimer et de marquer comme terminées des tâches. Utilisez les hooks useState pour gérer l'état.

Besoin d'aide sur React Hooks ?

Besoin d'aide sur un projet technique ? Decrivez-le pour des conseils personnalises.

Recevoir des conseils

Questions frequentes

Quelles sont les principales différences entre React Class Components et React Hooks ?
Les principaux avantages des Hooks sont le gain de lisibilité du code en permettant une utilisation plus claire du statut, des effets et d'autres fonctionnalités de React sans avoir recours aux classes. Les Hooks permettent également un plus grand contrôle sur le rendu des composants.
Comment puis-je migrer mon code existant de React Class Components vers les Hooks ?
La migration commence par identifier les méthodes de cycle de vie et d'état dans votre component class. Ensuite, vous remplacez ces méthodes par des Hooks appropriés comme useState pour le statut et useEffect pour les effets de bord. Assurez-vous de tester votre composant après la migration pour vous assurer qu'il fonctionne correctement.
Quels sont les avantages de utiliser React Hooks plutôt que les classes ?
Les Hooks offrent une meilleure lisibilité et maintenabilité du code grâce à leur organisation logique. Ils permettent également un plus grand contrôle sur le rendu des composants, réduisant ainsi la complexité du code. De plus, ils facilitent la réutilisation de logique entre les composants.

Pages liees

Chaque semaine, le meilleur de la tech francaise

Tendances, salaires, outils et opportunites — directement dans votre boite mail.

Gratuit. Desabonnement en un clic. Pas de spam.