Interactivité avec React : évènements et état
=============================================

* Précédent
* Aperçu : Client-side JavaScript frameworks
* Suivant  (en-US)

Après avoir organisé nos composants, il est maintenant temps de faire évoluer l'interface utilisateur de notre application afin que celle-ci ne soit plus statique mais interactive et permette de modifier les choses. C'est ce que nous allons faire dans cet article, en nous penchant sur les évènements et l'état, pour aboutir à une application dans laquelle nous pouvons ajouter des tâches, les supprimer et les marquer comme terminées.

|  |  |
| --- | --- |
| Prérequis : | Connaissances des fondamentaux en HTML, CSS, et JavaScript, connaissance du terminal/de la ligne de commande. |
| Objectifs : | Apprendre comment gérer les évènements et l'état en React, et les utiliser pour commencer à rendre notre application de liste de tâches interactive. |

Gestion des évènements
----------------------

Si vous n'avez pas utilisé de *framework* JavaScript jusqu'à présent, vous avez peut-être l'habitude de disposer d'un fichier JavaScript distinct, dans lequel vous interrogez certains nœuds du DOM et leur attachez des gestionnaires d'évènements. Par exemple :


```jsx
const btn = document.querySelector("button");

btn.addEventListener("click", () => {
  alert("coucou !");
});
```


Avec React, nous écrivons des gestionnaires d'évènements directement sur les éléments de notre JSX, comme ceci :


```jsx
<button type="button" onClick={() => alert("coucou !")}>
 Dire coucou !
</button>
```


**Note :** Cela peut sembler contre-intuitif au regard des bonnes pratiques qui déconseillent l'utilisation de gestionnaires d'évènements en ligne sur le HTML, mais n'oubliez pas que JSX fait partie du code JavaScript.

Dans l'exemple ci-dessus, nous ajoutons un attribut `onClick` à l'élément `<bouton>`. La valeur de cet attribut est une fonction qui déclenche une simple alerte.

L'attribut `onClick` a une signification particulière ici : il indique à React d'exécuter une fonction donnée lorsque la personne clique sur le bouton. Il y a quelques autres choses à noter :

* L'écriture de `onClick` en *camel case* est importante : JSX ne reconnaîtra pas `onclick` (ce mot-clé est déjà utilisé en JavaScript pour représenter le gestionnaire d'évènement standard `onclick`).
* En JSX, tous les gestionnaires d'évènements suivent ce format : `on`, suivi du nom de l'évènement.

Appliquons cela à notre application en commençant par le composant `Form.js`.

### Gérer la soumission du formulaire

Au début de la fonction du composant `Form()`, créez une fonction nommée `handleSubmit()`. Cette fonction doit empêcher le comportement par défaut de l'évènement `submit` puis déclencher une alerte avec un message de votre choix. Vous devriez obtenir une fonction comme celle-ci :


```jsx
function handleSubmit(e) {
  e.preventDefault();
  alert("Coucou le monde !");
}
```


Pour que cette fonction soit utilisée, ajoutez un attribut `onSubmit` à l'élément `<form>` en utilisant `handleSubmit` comme valeur :


```jsx
<form onSubmit={handleSubmit}>
```


Maintenant, si vous revenez à votre navigateur et cliquez sur le bouton « Ajouter », votre navigateur vous montrera une boîte de dialogue d'alerte avec les mots « Coucou le monde » ou ce que vous avez choisi d'y écrire.

Fonctions de rappel passées en *props*
--------------------------------------

Dans les applications React, l'interactivité est rarement confinée à un seul composant : les évènements qui se produisent dans un composant affecteront d'autres parties de l'application. Lorsque nous commençons à pouvoir créer de nouvelles tâches, ce qui se produit dans le composant `<Form />` aura un impact sur la liste rendue dans `<App />`.

Nous voulons que la fonction `handleSubmit()` serve à créer une nouvelle tâche, nous avons donc besoin d'un moyen de passer des informations de `<Form />` à `<App />`. Nous ne pouvons pas transmettre des données de l'enfant au parent de la même manière que nous transmettons des données du parent à l'enfant via les *props* standard. Au lieu de cela, nous pouvons écrire une fonction dans `<App />` qui attendra des données de notre formulaire comme entrée, puis passer cette fonction à `<Form />` comme une *prop*. Cette fonction passée en tant que *prop* est appelée *prop callback* (qu'on peut traduire comme « fonction de rappel passée en prop »). Une fois que nous avons notre *prop callback*, nous pouvons l'appeler dans `<Form />` pour envoyer les bonnes données à `<App />`.

### Gestion de la soumission du formulaire via des fonctions de rappel

En haut de la fonction `App()` pour le composant éponyme, créez une fonction nommée `addTask()` prenant un seul paramètre `name` :


```jsx
function addTask(name) {
  alert(name);
}
```


Ensuite, nous allons passer `addTask()` dans `<Form />` comme une *prop*. La *prop* peut prendre le nom que vous voulez, toutefois, mieux vaut que celui-ci soit clair et compréhensible (cela pourra vous aider plus tard). Un nom `addTask` fait l'affaire, car il correspond au nom de la fonction et à son effet. Mettez alors à jour l'appel du composant `<Form />` comme suit :


```jsx
<Form addTask={addTask} />
```


Enfin, vous pouvez utiliser cette *prop* dans la fonction `handleSubmit()` de votre composant `<Form />` ! Mettez-le à jour comme suit :


```jsx
function handleSubmit(e) {
  e.preventDefault();
  props.addTask("Dire bonjour !");
}
```


Cliquer sur le bouton « Ajouter » dans votre navigateur prouvera que la fonction de rappel `addTask()` fonctionne, mais ce serait bien si nous pouvions faire en sorte que l'alerte nous montre ce que nous tapons dans notre champ de saisie ! C'est ce que nous allons faire maintenant.

**Note :** Nous avons décidé d'utiliser `addTask` comme nom pour notre *prop callback* afin de comprendre son rôle rapidement. Une autre convention commune que vous pouvez rencontrer dans le code React consiste à préfixer les noms des *prop* qui sont des fonctions avec `on`, suivi du nom de l'évènement qui les déclenchera. Par exemple, nous aurions pu donner à notre formulaire une *prop* `onSubmit` avec la valeur de `addTask`.

L'état et le *hook* `useState'
------------------------------

Jusqu'à présent, nous avons utilisé des *props* pour transmettre des données à travers nos composants et cela nous a été bien utile. Maintenant que nous devons gérer des saisies et des mises à jour de données, nous avons besoin de quelque chose en plus.

D'une part, les props proviennent du parent d'un composant. Notre `<Form />` n'héritera pas d'un nouveau nom pour notre tâche. Notre élément `<input />` vit directement à l'intérieur de `<Form />`, donc `<Form/>` sera directement responsable de la création de ce nouveau nom. Nous ne pouvons pas demander à `<Form />` de créer spontanément ses propres *props*, mais nous pouvons lui demander de suivre certaines de ses propres données pour nous. Les données de ce type, qu'un composant possède lui-même, forment son **état** (*state* en anglais). L'état est un autre outil puissant de React : les composants sont *propriétaires* de leur état, mais peuvent aussi *mettre à jour* celui-ci ultérieurement. Alors qu'il n'est pas possible de mettre à jour les *props* qu'un composant reçoit, mais seulement de les lire.

React fournit une variété de fonctions spéciales qui nous permettent de fournir de nouvelles capacités aux composants, comme cet état. Ces fonctions sont appelées ***hooks***. Le *hook* `useState`, comme son nom l'indique, est précisément celui dont nous avons besoin pour donner un état à notre composant.

Pour utiliser un *hook* React, nous devons l'importer depuis le module React. Dans le fichier `Form.js`, changez la toute première ligne afin d'avoir ceci :


```jsx
import React, { useState } from "react";
```


Cela nous permet d'importer la fonction `useState()` afin de l'utiliser n'importe où dans ce fichier.

La fonction `useState()` crée un état pour un composant, et son seul paramètre détermine la *valeur initiale* de cet état. Elle retourne deux choses : l'état, et une fonction qui peut être utilisée pour mettre à jour l'état plus tard.

Cela fait beaucoup de choses à assimiler d'un coup. Voyons ce que ça donne dans la pratique. Nous allons créer un état `name`, et une fonction pour mettre à jour cet état `name`.

Écrivez ce qui suit au-dessus de votre fonction `handleSubmit()`, dans `Form()` :


```jsx
const [name, setName] = useState("Utiliser les hooks !");
```


Que se passe-t-il dans cette ligne de code ?

* Nous définissons la valeur initiale de `name` comme étant « Utiliser les hooks ».
* Nous définissons une fonction `setName()` dont le rôle est de modifier `name`.
* `useState()` renvoie ces deux valeurs et nous utilisons la décomposition de tableaux pour les capturer dans des variables séparées.
### Lecture de l'état

Vous pouvez voir l'état `name` en action tout de suite. Ajoutez un attribut `value` dans le champ du formulaire, et utilisez `name` pour sa valeur. Votre navigateur affichera alors « Utiliser les hooks » à l'intérieur du champ.


```jsx
<input
 type="text"
 id="new-todo-input"
 className="input input\_\_lg"
 name="text"
 autoComplete="off"
 value={name}
/>
```


Changez « Utiliser les hooks » en une chaîne vide une fois que vous avez terminé. C'est ce que nous voulons pour notre état initial.


```jsx
const [name, setName] = useState("");
```

### Lire ce qui a été saisi par la personne

Avant de pouvoir changer la valeur de `name`, nous devons capturer ce qui est saisi dans le formulaire. Pour cela, on utilise le gestionnaire d'évènement `onChange`. Écrivons une fonction `handleChange()`, et écoutons l'évènement sur l'élément `<input />`.


```jsx
// vers le haut du composant `Form`
function handleChange(e) {
  console.log("Saisie en cours !");
}

// Plus bas vers l'instruction return
<input
 type="text"
 id="new-todo-input"
 className="input input\_\_lg"
 name="text"
 autoComplete="off"
 value={name}
 onChange={handleChange}
/>;
```


Actuellement, la valeur du champ ne changera pas lors de la saisie, mais votre navigateur affichera « Saisie en cours ! » dans la console JavaScript. Cela nous permet de vérifier que notre gestionnaire d'évènements est bien attaché au champ. Afin de changer la valeur du champ, nous devons utiliser notre fonction `handleChange()` pour mettre à jour notre état `name`.

Pour lire le contenu du champ, au fur et à mesure de la saisie, on peut utiliser la propriété `value` du champ. Nous pouvons le faire dans `handleChange()` en lisant `e.target.value`. `e.target` représente l'élément qui a déclenché l'évènement `change`, ce qui correspond ici à notre champ. `e.target.value` correspond donc au texte que le champ contient.

Vous pouvez afficher cette valeur dans la console du navigateur à l'aide de `console.log()`.


```jsx
function handleChange(e) {
  console.log(e.target.value);
}
```

### Mise à jour de l'état

La journalisation n'est pas suffisante, nous voulons réellement stocker l'état mis à jour du nom lorsque la valeur saisie change ! Changez `console.log()` en `setName()`, comme indiqué ici :


```jsx
function handleChange(e) {
  setName(e.target.value);
}
```


Maintenant, nous devons modifier notre fonction `handleSubmit()` pour qu'elle appelle `props.addTask` en utilisant le nom comme argument. Vous rappelez vous de notre *prop callback* ? Il nous servira à renvoyer la tâche vers le composant `<App />`, afin que nous puissions l'ajouter à notre liste de tâches par la suite.

Une bonne pratique consiste à effacer l'entrée après que le formulaire a été envoyé. Nous appellerons donc `setName()` de nouveau avec une chaîne vide pour le faire :


```jsx
function handleSubmit(e) {
  e.preventDefault();
  props.addTask(name);
  setName("");
}
```


Enfin, vous pouvez taper quelque chose dans le champ de saisie de votre navigateur et cliquer sur « Ajouter ». Ce que vous avez tapé apparaîtra dans une boîte de dialogue d'alerte.

À cet instant, votre fichier `Form.js` devrait ressembler à ceci :


```jsx
import React, { useState } from "react";

function Form(props) {
  const [name, setName] = useState("");

  function handleChange(e) {
    setName(e.target.value);
  }

  function handleSubmit(e) {
    e.preventDefault();
    props.addTask(name);
    setName("");
  }
  return (
    <form onSubmit={handleSubmit}>
 <h2 className="label-wrapper">
 <label htmlFor="new-todo-input" className="label\_\_lg">
 Qu'y a-t-il à faire&nbsp;?
 </label>
 </h2>
 <input
 type="text"
 id="new-todo-input"
 className="input input\_\_lg"
 name="text"
 autoComplete="off"
 value={name}
 onChange={handleChange}
 />
 <button type="submit" className="btn btn\_\_primary btn\_\_lg">
 Ajouter
 </button>
 </form>
  );
}

export default Form;
```


**Note :** Vous remarquerez que vous pouvez soumettre des tâches vides en appuyant simplement sur le bouton Ajouter sans saisir de nom de tâche. Pouvez-vous penser à un moyen d'empêcher l'ajout de tâches vides ? En guise d'indice, vous devez probablement ajouter une sorte de vérification dans la fonction `handleSubmit()`.

Assembler le tout : ajouter une tâche
-------------------------------------

Maintenant que nous avons vu comment utiliser des évènements, des *callback props*, et des *hooks*, nous pouvons implémenter la fonctionnalité de notre application qui permettra d'ajouter une nouvelle tâche depuis le navigateur.

### Les tâches comme état

Importez `useState` dans `App.js`, pour pouvoir stocker nos tâches dans l'état. Pour cela, mettez à jour votre ligne d'importation `React` avec ce qui suit :


```jsx
import React, { useState } from "react";
```


Nous voulons passer `props.tasks` dans le *hook* `useState()` : cela préservera son état initial. Ajoutez ce qui suit en haut de la définition de votre fonction `App()` :


```jsx
const [tasks, setTasks] = useState(props.tasks);
```


Maintenant, nous pouvons modifier `taskList` pour qu'il utilise `tasks` et non `props.tasks`. La déclaration de constante pour `taskList` devrait maintenant ressembler à ceci :


```jsx
const taskList = tasks.map((task) => (
  <Todo
 id={task.id}
 name={task.name}
 completed={task.completed}
 key={task.id}
 />
));
```

### Ajout d'une tâche

Nous avons maintenant un *hook* `setTasks` que nous pouvons utiliser dans notre fonction `addTask()` pour mettre à jour notre liste de tâches. Il y a cependant un problème : nous ne pouvons pas simplement passer l'argument `name` de `addTask()` dans `setTasks`, parce que `tasks` est un tableau d'objets alors que `name` est une chaîne de caractères. Si on essayait de faire ça, le tableau serait remplacé par la chaîne de caractères.

Tout d'abord, nous devons mettre `name` dans un objet qui a la même structure que nos tâches existantes. Dans la fonction `addTask()`, nous allons créer un objet `newTask` à ajouter au tableau.

Nous devons ensuite créer un nouveau tableau auquel nous ajoutons cette nouvelle tâche, puis mettre à jour l'état des données de la tâche en fonction de ce nouvel état. Pour ce faire, nous pouvons utiliser la syntaxe de décomposition pour copier le tableau existant, et ajouter notre objet à la fin. Nous passons ensuite ce tableau dans `setTasks()` pour mettre à jour l'état.

En assemblant tout cela, votre fonction `addTask()` devrait ressembler à ceci :


```jsx
function addTask(name) {
  const newTask = { id: "id", name, completed: false };
  setTasks([...tasks, newTask]);
}
```


Vous pouvez maintenant utiliser le navigateur pour ajouter une tâche à nos données ! Tapez n'importe quoi dans le formulaire et cliquez sur « Ajouter » (ou appuyez sur la touche `Enter`) et vous verrez votre nouvelle tâche apparaître à l'écran !

**Toutefois, nous avons un autre problème**. Notre fonction `addTask()` donne le même `id` à chaque tâche. Ceci dégrade l'accessibilité et empêche React de distinguer les tâches futures avec la *prop* `key`. En fait, React affichera un avertissement dans la console des outils de développement du navigateur : « Attention : il y a deux enfants qui ont la même clé » (*"Warning: Encountered two children with the same key…"*).

Nous devons résoudre ce problème. La création d'identifiants uniques est un problème difficile, pour lequel la communauté JavaScript a écrit des bibliothèques utiles. Nous utiliserons nanoid parce qu'elle est minuscule et qu'elle fonctionne.

Assurez-vous d'être dans le répertoire racine de votre application, puis exécutez la commande suivante dans le terminal :

* Si vous utilisez npm

```bash
npm install nanoid
```

* Si vous utilisez yarn

```bash
yarn add nanoid
```


Maintenant, nous pouvons importer `nanoid` en haut de `App.js` afin de l'utiliser pour créer des identifiants uniques pour nos nouvelles tâches. Tout d'abord, incluez la ligne d'importation suivante au début du fichier `App.js`:


```jsx
import { nanoid } from "nanoid";
```


Maintenant, mettons à jour `addTask()` pour que chaque identifiant de tâche ait un préfixe `todo-` puis une chaîne unique générée par nanoid. Mettez à jour votre déclaration de constante `newTask` comme ceci :


```jsx
const newTask = { id: `todo-${nanoid()}`, name, completed: false };
```


Sauvegardez les fichiers édités, et réessayez votre application. Vous pouvez désormais ajouter des tâches sans avoir cet avertissement sur les identifiants en double.

Compter les tâches
------------------

Maintenant que nous pouvons ajouter de nouvelles tâches, vous pouvez remarquer un problème : notre titre indique 3 tâches restantes, peu importe le nombre de tâches que nous avons ! Nous pouvons résoudre ce problème en mesurant la longueur de `taskList` et en changeant le texte de notre titre en conséquence.

Ajoutez ceci dans votre définition de `App()`, avant l'instruction `return` :


```jsx
const headingText = `${taskList.length} tâches restantes`;
```


C'est presque correct, mais si notre liste ne contient qu'une seule tâche, l'intitulé utilisera toujours le mot « tâches ». Nous pouvons également en faire une variable. Mettez à jour le code que vous venez d'ajouter comme suit:


```jsx
const tasksWords =
  taskList.length !== 1 ? "tâches restantes" : "tâche restante";
const headingText = `${taskList.length} ${tasksWords}`;
```


Vous pouvez maintenant remplacer le contenu du texte de l'en-tête de la liste par la variable `headingText`. Mettez à jour votre élément `<h2>` comme suit :


```jsx
<h2 id="list-heading">{headingText}</h2>
```

Achèvement d'une tâche
----------------------

Vous avez peut-être remarqué que, lorsque vous cliquez sur une case à cocher, celle-ci est cochée et décochée de manière appropriée. C'est une fonctionnalité de HTML : le navigateur gère la mémoire des cases qui sont cochées ou décochées sans avoir besoin de notre aide. Toutefois, cela nous gène ici, car le fait de basculer une case à cocher ne change pas l'état de notre application React. Cela signifie que le navigateur et notre application sont désynchronisés. Nous devons écrire notre propre code pour synchroniser l'état du navigateur avec notre application.

### Constater le problème

Avant de corriger le problème, observons ce qui se passe.

Commençons par écrire une fonction `toggleTaskCompleted()` dans notre composant `App()`. Cette fonction aura un paramètre `id`, mais nous n'allons pas l'utiliser immédiatement. Pour l'instant, nous allons enregistrer la première tâche du tableau dans la console et nous allons inspecter ce qui se passe lorsque nous la cochons ou la décochons dans notre navigateur :

Ajoutez ceci juste au-dessus de la déclaration de la constante `taskList` :


```jsx
function toggleTaskCompleted(id) {
  console.log(tasks[0]);
}
```


Ensuite, nous allons ajouter `toggleTaskCompleted` aux *props* de chaque composant `<Todo />` rendu à l'intérieur de notre `taskList`. Mettez-le à jour comme ceci :


```jsx
const taskList = tasks.map((task) => (
  <Todo
 id={task.id}
 name={task.name}
 completed={task.completed}
 key={task.id}
 toggleTaskCompleted={toggleTaskCompleted}
 />
));
```


Ensuite, allez dans votre composant `Todo.js` et ajoutez un gestionnaire `onChange` à votre élément `<input />` qui utilise une fonction anonyme pour appeler `props.toggleTaskCompleted()` avec un paramètre de `props.id`. L'élément `<input />` devrait désormais ressembler à :


```jsx
<input
 id={props.id}
 type="checkbox"
 defaultChecked={props.completed}
 onChange={() => props.toggleTaskCompleted(props.id)}
/>
```


Enregistrez tout, puis revenez à votre navigateur. Remarquez que notre première tâche (Manger) est cochée. Ouvrez votre console JavaScript, puis cliquez sur la case à cocher à côté de Manger. La case est décochée, comme prévu. Votre console JavaScript affichera alors quelque chose comme ceci :
```

Object { id: "task-0", name: "Eat", completed: true }
```


La case est décochée dans le navigateur, mais notre console nous indique que la tâche est toujours terminée. Nous allons corriger cela !

### Synchronisation du navigateur avec nos données

Revoyons notre fonction `toggleTaskCompleted()` dans `App.js`. Nous voulons qu'elle change la propriété `completed` uniquement pour la tâche qui a été activée, et qu'elle laisse toutes les autres inchangées. Pour ce faire, nous allons utiliser `map()` sur la liste des tâches et changer seulement celle qui a été complétée.

Mettez à jour votre fonction `toggleTaskCompleted()` comme suit&,ns^::


```jsx
function toggleTaskCompleted(id) {
  const updatedTasks = tasks.map((task) => {
    // si cette tâche possède le même identifiant que la tâche éditée
    if (id === task.id) {
      // on utilise la décomposition objet afin
      // de construire un nouvel objet dont la
      // propriété `completed` est l'inverse
      return { ...task, completed: !task.completed };
    }
    return task;
  });
  setTasks(updatedTasks);
}
```


Ici, nous définissons une constante `updatedTasks` qui correspond au tableau `tasks` original. Si la propriété `id` de la tâche correspond à l'identifiant fourni à la fonction via le paramètre `id`, nous utilisons la syntaxe de décomposition pour créer un nouvel objet, et basculer la propriété `completed` de cet objet avant de le retourner. Si elle ne correspond pas, nous retournons l'objet original.

Ensuite, nous appelons `setTasks()` avec ce nouveau tableau afin de mettre à jour notre état.

Suppression d'une tâche
-----------------------

La suppression d'une tâche suivra un schéma similaire à celui du changement d'état : nous devons définir une fonction pour mettre à jour notre état, puis passer cette fonction dans `<Todo />` en tant que prop et l'appeler quand le bon évènement se produit.

### La fonction de rappel `deleteTask()`

Ici, nous allons commencer par écrire une fonction `deleteTask()` dans votre composant `App`. Comme `toggleTaskCompleted()`, cette fonction prendra un paramètre `id`. Pour commencer, nous allons uniquement afficher cet identifiant dans la console. Ajoutez ce qui suit sous `toggleTaskCompleted()` :


```jsx
function deleteTask(id) {
  console.log(id);
}
```


Ensuite, ajoutez une autre *prop callback* à notre tableau de composants `<Todo />` :


```jsx
const taskList = tasks.map((task) => (
  <Todo
 id={task.id}
 name={task.name}
 completed={task.completed}
 key={task.id}
 toggleTaskCompleted={toggleTaskCompleted}
 deleteTask={deleteTask}
 />
));
```


Dans `Todo.js`, nous voulons appeler `props.deleteTask()` lorsque nous appuyons sur le bouton « Supprimer ». `deleteTask()` a besoin de connaître l'identifiant de la tâche qui l'a appelé, afin de pouvoir supprimer la bonne tâche de l'état.

Mettez à jour le bouton "Supprimer" dans `Todo.js`, comme ceci :


```jsx
<button
 type="button"
 className="btn btn\_\_danger"
 onClick={() => props.deleteTask(props.id)}>
 Supprimer <span className="visually-hidden">{props.name}</span>
</button>
```


Maintenant, lorsque vous cliquez sur l'un des boutons « Supprimer » de l'application, la console de votre navigateur devrait enregistrer l'identifiant de la tâche concernée.

Suppression des tâches de l'état et de l'interface utilisateur
--------------------------------------------------------------

Maintenant que nous savons que `deleteTask()` est invoquée correctement, nous pouvons appeler notre *hook* `setTasks()` dans `deleteTask()` pour supprimer réellement cette tâche de l'état de l'application afin que celui-ci corresponde à ce qui est présenté visuellement. Puisque `setTasks()` attend un tableau comme argument, nous devons lui fournir un nouveau tableau qui copie les tâches existantes et *exclut* la tâche dont l'identifiant correspond à celui passé à `deleteTask()`.

C'est l'occasion idéale d'utiliser `filter()`. Nous pouvons tester chaque tâche, et exclure une tâche du nouveau tableau si sa propriété `id` correspond à l'argument `id` passé à `deleteTask()`.

Mettez à jour la fonction `deleteTask()` dans votre fichier `App.js` comme suit :


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


Essayez à nouveau votre application. Vous devriez maintenant pouvoir supprimer une tâche de votre application !

Résumé
------

Cet article était dense. Nous avons vu comment React gère les évènements et les états. Nous avons implémenté une fonctionnalité permettant d'ajouter et de supprimer des tâches, et de marquer des tâches comme étant terminées. Nous en avons presque terminé. Dans le prochain article, nous implémenterons une fonctionnalité pour modifier les tâches existantes, filtrer la liste des tâches entre toutes les tâches, les tâches terminées et les tâches incomplètes. Nous en profiterons pour aborder le rendu conditionnel de l'interface utilisateur.

* Précédent
* Aperçu : Client-side JavaScript frameworks
* Suivant  (en-US)