Ajouter de l’interactivitĂ©

Certaines choses Ă  l’écran se mettent Ă  jour en rĂ©ponse aux actions de l’utilisateur. Par exemple, en cliquant sur une galerie d’images, l’image active change. En React, les donnĂ©es qui changent au fil du temps sont appelĂ©es Ă©tat. Vous pouvez ajouter un Ă©tat Ă  n’importe quel composant et le mettre Ă  jour quand nĂ©cessaire. Dans ce chapitre, vous apprendrez Ă  Ă©crire des composants qui gĂšrent des interactions, mettent Ă  jour leur Ă©tat et ajustent leur affichage au fil du temps.

Réagir aux événements

React vous permet d’ajouter des gestionnaires d’évĂ©nements Ă  votre JSX. Les gestionnaires d’évĂ©nements sont vos propres fonctions qui seront dĂ©clenchĂ©es en rĂ©ponse aux interactions de l’utilisateur telles que des clics, survols, activations de champs de saisie de formulaires, etc.

Les composants natifs tels que <button> ne prennent en charge que les Ă©vĂ©nements natifs du navigateur tels que onClick. Cependant, vous pouvez Ă©galement crĂ©er vos propres composants et donner Ă  leurs props de gestionnaires d’évĂ©nements des noms spĂ©cifiques Ă  l’application, selon vos besoins.

export default function App() {
  return (
    <Toolbar
      onPlayMovie={() => alert('Lecture en cours !')}
      onUploadImage={() => alert('TĂ©lĂ©versement en cours !')}
    />
  );
}

function Toolbar({ onPlayMovie, onUploadImage }) {
  return (
    <div>
      <Button onClick={onPlayMovie}>
        Voir le film
      </Button>
      <Button onClick={onUploadImage}>
        Téléverser une image
      </Button>
    </div>
  );
}

function Button({ onClick, children }) {
  return (
    <button onClick={onClick}>
      {children}
    </button>
  );
}

PrĂȘt·e Ă  en apprendre davantage ?

Lisez RĂ©agir aux Ă©vĂ©nements pour apprendre comment ajouter des gestionnaires d’évĂ©nements.

En savoir plus

L’état : la mĂ©moire d’un composant

Les composants ont souvent besoin de modifier ce qui est affichĂ© Ă  l’écran en rĂ©ponse Ă  une interaction. Par exemple, saisir du texte dans un formulaire devrait mettre Ă  jour le champ de saisie, cliquer sur « suivant Â» dans un carrousel d’images devrait changer l’image affichĂ©e, cliquer sur « acheter Â» ajoute un produit au panier d’achats. Les composants ont besoin de « se souvenir Â» de certaines choses : la valeur saisie, l’image active, le panier d’achats. En React, ce type de mĂ©moire spĂ©cifique au composant est appelĂ© Ă©tat.

Vous pouvez ajouter un Ă©tat Ă  un composant avec un Hook useState. Les Hooks sont des fonctions spĂ©ciales qui permettent Ă  vos composants d’utiliser des fonctionnalitĂ©s de React (l’état en est une). Le Hook useState vous permet de dĂ©clarer une variable d’état. Il prend l’état initial en argument et renvoie une paire de valeurs : l’état actuel et une fonction qui vous permet de le modifier.

const [index, setIndex] = useState(0);
const [showMore, setShowMore] = useState(false);

Voici comment une galerie d’images utilise et met Ă  jour l’état lors d’un clic :

import { useState } from 'react';
import { sculptureList } from './data.js';

export default function Gallery() {
  const [index, setIndex] = useState(0);
  const [showMore, setShowMore] = useState(false);
  const hasNext = index < sculptureList.length - 1;

  function handleNextClick() {
    if (hasNext) {
      setIndex(index + 1);
    } else {
      setIndex(0);
    }
  }

  function handleMoreClick() {
    setShowMore(!showMore);
  }

  let sculpture = sculptureList[index];
  return (
    <>
      <button onClick={handleNextClick}>
        Suivant
      </button>
      <h2>
        <i>{sculpture.name} </i>
        par {sculpture.artist}
      </h2>
      <h3>
        ({index + 1} sur {sculptureList.length})
      </h3>
      <button onClick={handleMoreClick}>
        {showMore ? 'Masquer' : 'Afficher'} les détails
      </button>
      {showMore && <p>{sculpture.description}</p>}
      <img
        src={sculpture.url}
        alt={sculpture.alt}
      />
    </>
  );
}

PrĂȘt·e Ă  en apprendre davantage ?

Lisez L’état : la mĂ©moire d’un composant pour apprendre comment mĂ©moriser une valeur et la mettre Ă  jour lors d’une interaction.

En savoir plus

Rendu et Commit

Avant que vos composants ne soient affichĂ©s Ă  l’écran, React doit effectuer leur rendu. Comprendre les Ă©tapes de ce processus vous aidera Ă  rĂ©flĂ©chir Ă  l’exĂ©cution de votre code et Ă  expliquer son comportement.

Imaginez que vos composants soient des cuisiniers dans un restaurant, assemblant des plats savoureux Ă  partir d’ingrĂ©dients. Dans ce scĂ©nario, React est le serveur qui prend les commandes des clients et leur apporte leurs plats. Ce processus de demande et de service de l’UI comporte trois Ă©tapes :

  1. Déclencher un rendu (envoyer la commande du client à la cuisine)
  2. Faire le rendu du composant (préparer la commande en cuisine)
  3. Mettre Ă  jour le DOM (phase de Commit ; revient Ă  dĂ©poser la commande sur la table du client)
  1. React agit comme un serveur dans un restaurant, qui récupÚre les commandes des utilisateurs et les transmet à la cuisine des composants.
    Déclencher
  2. Le chef Card fournit Ă  React un nouveau composant Card.
    Faire le rendu
  3. React dĂ©pose le Card sur la table de l’utilisateur.
    Mettre Ă  jour (Commit)

Illustré par Rachel Lee Nabors

PrĂȘt·e Ă  en apprendre davantage ?

Lisez Rendu et Commit pour apprendre sur le cycle de vie d’une mise à jour de l’interface.

En savoir plus

L’état est un instantanĂ©

Contrairement aux variables JavaScript classiques, une variable d’état dans React se comporte davantage comme une photo instantanĂ©e. Lui affecter une nouvelle valeur ne change pas la variable d’état que vous avez dĂ©jĂ , mais dĂ©clenche plutĂŽt un nouveau rendu. Ça peut surprendre au dĂ©but !

console.log(count); // 0
setCount(count + 1); // EntraĂźnera un nouveau rendu avec la valeur 1
console.log(count); // Toujours 0 !

Ce comportement vous aide Ă  Ă©viter des bugs subtils. Voici une petite appli de discussion. Essayez de deviner ce qui se passe si vous appuyez sur « Envoyer Â» d’abord, et ensuite changez le destinataire pour Bob. Quel nom apparaĂźtra dans le alert cinq secondes plus tard ?

import { useState } from 'react';

export default function Form() {
  const [to, setTo] = useState('Alice');
  const [message, setMessage] = useState('Hello');

  function handleSubmit(e) {
    e.preventDefault();
    setTimeout(() => {
      alert(`Vouz avez dit ${message} Ă  ${to}`);
    }, 5000);
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        À :{' '}
        <select
          value={to}
          onChange={e => setTo(e.target.value)}>
          <option value="Alice">Alice</option>
          <option value="Bob">Bob</option>
        </select>
      </label>
      <textarea
        placeholder="Message"
        value={message}
        onChange={e => setMessage(e.target.value)}
      />
      <button type="submit">Envoyer</button>
    </form>
  );
}

PrĂȘt·e Ă  en apprendre davantage ?

Lisez L’état comme un instantanĂ© pour comprendre pourquoi un Ă©tat semble « fixe Â» et immuable Ă  l’intĂ©rieur des gestionnaires d’évĂ©nements.

En savoir plus

Cumuler les mises Ă  jour d’un mĂȘme Ă©tat

Ce composant comporte un bug : cliquer sur « +3 Â» n’incrĂ©mente le score qu’une seule fois.

import { useState } from 'react';

export default function Counter() {
  const [score, setScore] = useState(0);

  function increment() {
    setScore(score + 1);
  }

  return (
    <>
      <button onClick={() => increment()}>+1</button>
      <button onClick={() => {
        increment();
        increment();
        increment();
      }}>+3</button>
      <h1>Score: {score}</h1>
    </>
  )
}

L’état comme un instantanĂ© en explique la raison. Affecter une nouvelle valeur Ă  un Ă©tat dĂ©clenchera un nouveau rendu, mais ne change pas sa valeur dans le code en cours d’exĂ©cution. Ainsi, score reste Ă  0 juste aprĂšs avoir appelĂ© setScore(score + 1).

console.log(score); // 0
setScore(score + 1); // setScore(0 + 1);
console.log(score); // 0
setScore(score + 1); // setScore(0 + 1);
console.log(score); // 0
setScore(score + 1); // setScore(0 + 1);
console.log(score); // 0

Vous pouvez corriger ça en passant une fonction de mise Ă  jour lorsque vous affectez une nouvelle valeur Ă  l’état. Voyez comme le remplacement de setScore(score + 1) par setScore(s => s + 1) corrige le bouton « +3 Â». Ça vous permet de cumuler plusieurs mises Ă  jour d’un mĂȘme Ă©tat.

import { useState } from 'react';

export default function Counter() {
  const [score, setScore] = useState(0);

  function increment() {
    setScore(s => s + 1);
  }

  return (
    <>
      <button onClick={() => increment()}>+1</button>
      <button onClick={() => {
        increment();
        increment();
        increment();
      }}>+3</button>
      <h1>Score: {score}</h1>
    </>
  )
}

PrĂȘt·e Ă  en apprendre davantage ?

Lisez Cumuler les sĂ©rie de mises Ă  jour d’un mĂȘme Ă©tat pour apprendre comment cumuler plusieurs mises Ă  jour d’une mĂȘme variable d’état.

En savoir plus

Mettre Ă  jour les objets d’un Ă©tat

Un Ă©tat peut contenir n’importe quel type de valeur JavaScript, y compris des objets. Cependant, vous ne devez pas changer directement les objets et les tableaux que vous stockez dans l’état React. Au lieu de cela, lorsque vous voulez mettre Ă  jour un objet ou un tableau, vous devez en crĂ©er un nouveau (ou faire une copie de l’existant), puis mettre Ă  jour l’état pour utiliser cette copie.

GĂ©nĂ©ralement, vous utiliserez la syntaxe de spread ... pour copier les objets et les tableaux que vous souhaitez modifier. Par exemple, la mise Ă  jour d’un objet imbriquĂ© pourrait ressembler Ă  ceci :

import { useState } from 'react';

export default function Form() {
  const [person, setPerson] = useState({
    name: 'Niki de Saint Phalle',
    artwork: {
      title: 'Blue Nana',
      city: 'Hamburg',
      image: 'https://i.imgur.com/Sd1AgUOm.jpg',
    }
  });

  function handleNameChange(e) {
    setPerson({
      ...person,
      name: e.target.value
    });
  }

  function handleTitleChange(e) {
    setPerson({
      ...person,
      artwork: {
        ...person.artwork,
        title: e.target.value
      }
    });
  }

  function handleCityChange(e) {
    setPerson({
      ...person,
      artwork: {
        ...person.artwork,
        city: e.target.value
      }
    });
  }

  function handleImageChange(e) {
    setPerson({
      ...person,
      artwork: {
        ...person.artwork,
        image: e.target.value
      }
    });
  }

  return (
    <>
      <label>
        Nom :
        <input
          value={person.name}
          onChange={handleNameChange}
        />
      </label>
      <label>
        Titre :
        <input
          value={person.artwork.title}
          onChange={handleTitleChange}
        />
      </label>
      <label>
        Ville :
        <input
          value={person.artwork.city}
          onChange={handleCityChange}
        />
      </label>
      <label>
        Image :
        <input
          value={person.artwork.image}
          onChange={handleImageChange}
        />
      </label>
      <p>
        <i>{person.artwork.title}</i>
        {' par '}
        {person.name}
        <br />
        (Ă  {person.artwork.city})
      </p>
      <img
        src={person.artwork.image}
        alt={person.artwork.title}
      />
    </>
  );
}

Si la copie d’objets dans le code devient fastidieuse, vous pouvez utiliser une bibliothĂšque telle que Immer pour simplifier le code :

{
  "dependencies": {
    "immer": "1.7.3",
    "react": "latest",
    "react-dom": "latest",
    "react-scripts": "latest",
    "use-immer": "0.5.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "devDependencies": {}
}

PrĂȘt·e Ă  en apprendre davantage ?

Lisez Mettre Ă  jour les objets d’un Ă©tat pour apprendre comment mettre Ă  jour correctement les objets d’une variable d’état.

En savoir plus

Mettre Ă  jour les tableaux d’un Ă©tat

Les tableaux sont un autre type d’objet modifiable en JavaScript que vous pouvez stocker dans un Ă©tat et que vous devez traiter comme Ă©tant en lecture seule. Tout comme avec les objets, lorsque vous souhaitez mettre Ă  jour un tableau stockĂ© dans un Ă©tat, vous devez en crĂ©er un nouveau (ou en copier un existant), puis affecter le nouveau tableau dans l’état :

import { useState } from 'react';

const initialList = [
  { id: 0, title: 'Big Bellies', seen: false },
  { id: 1, title: 'Lunar Landscape', seen: false },
  { id: 2, title: 'Terracotta Army', seen: true },
];

export default function BucketList() {
  const [list, setList] = useState(
    initialList
  );

  function handleToggle(artworkId, nextSeen) {
    setList(list.map(artwork => {
      if (artwork.id === artworkId) {
        return { ...artwork, seen: nextSeen };
      } else {
        return artwork;
      }
    }));
  }

  return (
    <>
      <h1>Liste d’Ɠuvres d’art</h1>
      <h2>Ma liste Ă  voir absolument :</h2>
      <ItemList
        artworks={list}
        onToggle={handleToggle} />
    </>
  );
}

function ItemList({ artworks, onToggle }) {
  return (
    <ul>
      {artworks.map(artwork => (
        <li key={artwork.id}>
          <label>
            <input
              type="checkbox"
              checked={artwork.seen}
              onChange={e => {
                onToggle(
                  artwork.id,
                  e.target.checked
                );
              }}
            />
            {artwork.title}
          </label>
        </li>
      ))}
    </ul>
  );
}

Si la copie de tableaux dans le code devient fastidieuse, vous pouvez utiliser une bibliothĂšque telle que Immer pour simplifier le code :

{
  "dependencies": {
    "immer": "1.7.3",
    "react": "latest",
    "react-dom": "latest",
    "react-scripts": "latest",
    "use-immer": "0.5.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "devDependencies": {}
}

PrĂȘt·e Ă  en apprendre davantage ?

Lisez Mettre Ă  jour les tableaux d’un Ă©tat pour apprendre comment mettre Ă  jour correctement les tableaux d’une variable d’état.

En savoir plus

Et maintenant ?

Allez sur RĂ©agir aux Ă©vĂ©nements pour commencer Ă  lire ce chapitre page par page !

Ou alors, si vous ĂȘtes dĂ©jĂ  Ă  l’aise avec ces sujets, pourquoi ne pas explorer comment gĂ©rer l’état ?