Passer des props à un composant

Les composants React utilisent des props pour communiquer entre eux. Chaque composant parent peut passer des informations à ses composants enfants en leur donnant des props. Les props vous rappellent peut-être les attributs HTML, mais vous pouvez y passer n’importe quelle valeur JavaScript, y compris des objets et des fonctions.

Vous allez apprendre

  • Comment passer des props à un composant
  • Comment lire les props au sein d’un composant
  • Comment spécifier des valeurs par défaut pour les props
  • Comment passer du JSX à un composant
  • Comment les props peuvent changer au fil du temps

Props standardisées

Les props sont des informations que vous passez à une balise JSX. Par exemple, une balise <img> compte parmi ses props className, src, alt, width et height :

function Avatar() {
  return (
    <img
      className="avatar"
      src="https://i.imgur.com/1bX5QH6.jpg"
      alt="Lin Lanying"
      width={100}
      height={100}
    />
  );
}

export default function Profile() {
  return (
    <Avatar />
  );
}

Les props que vous pouvez passer à une balise <img> sont bien définies (ReactDOM respecte le standard HTML). Mais vous pouvez passer les props de votre choix à vos propres composants, tels qu’<Avatar>, pour les personnaliser. Voici comment faire !

Passer des props à un composant

Dans le code qui suit, le composant Profile ne passe aucune prop à son composant fils, Avatar :

export default function Profile() {
return (
<Avatar />
);
}

Vous pouvez donner quelques props à Avatar en deux étapes.

Étape 1 : passez des props au composant enfant

Commencez par passer quelques props à Avatar. Par exemple, passons deux props : person (un objet) et size (un nombre) :

export default function Profile() {
return (
<Avatar
person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}
size={100}
/>
);
}

Remarque

Si les doubles accolades après person= vous déroutent, souvenez-vous qu’il s’agit juste d’un littéral objet entre les accolades JSX.

Vous pouvez maintenant lire ces props au sein du composant Avatar.

Étape 2 : lisez les props dans le composant enfant

Vous pouvez lire ces props en listant leurs noms person, size séparés par des virgules entre ({ et }) immédiatement après function Avatar. Ça vous permet de les utiliser dans le code d’Avatar, comme si vous aviez une variable locale.

function Avatar({ person, size }) {
// person et size sont disponibles ici
}

Ajoutez un peu de logique à Avatar qui se base sur les props person et size pour le rendu, et vous y serez !

Vous pouvez désormais configurer Avatar pour s’afficher de différentes façons selon les valeurs de ses props. Essayez de jouer avec ces valeurs !

import { getImageUrl } from './utils.js';

function Avatar({ person, size }) {
  return (
    <img
      className="avatar"
      src={getImageUrl(person)}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}

export default function Profile() {
  return (
    <div>
      <Avatar
        size={100}
        person={{
          name: 'Katsuko Saruhashi',
          imageId: 'YfeOqp2'
        }}
      />
      <Avatar
        size={80}
        person={{
          name: 'Aklilu Lemma',
          imageId: 'OKS67lh'
        }}
      />
      <Avatar
        size={50}
        person={{
          name: 'Lin Lanying',
          imageId: '1bX5QH6'
        }}
      />
    </div>
  );
}

Les props vous permettent de réfléchir aux composants parent et enfant indépendamment. Par exemple, vous pouvez modifier les props person et size au sein de Profile sans avoir à vous préoccuper de comment Avatar les utilise. De la même façon, vous pouvez modifier l’utilisation interne de ces props par Avatar sans vous préoccuper de Profile.

Vous pouvez concevoir les props comme des « molettes » que vous pouvez ajuster. Elles jouent le même rôle que les arguments des fonctions — en fait, les props sont le seul argument de votre composant ! Les fonctions composants React ne prennent qu’un argument, qui est l’objet props :

function Avatar(props) {
let person = props.person;
let size = props.size;
// ...
}

Le plus souvent vous n’aurez pas besoin de l’objet props lui-même dans son intégralité, vous le déstructurerez donc en props individuelles.

Piège

N’oubliez pas la paire d’accolades { et } entre les parenthèses ( et ) lorsque vous déclarez les props dans la signature de votre fonction composant :

function Avatar({ person, size }) {
// ...
}

Cette syntaxe est appelée « déstructuration » (le MDN parle de façon discutable de « décomposition », qu’il amalgame en prime avec le rest/spread, NdT) et c’est l’équivalent concis de la lecture des propriétés depuis le paramètre de la fonction :

function Avatar(props) {
let person = props.person;
let size = props.size;
// ...
}

Spécifier une valeur par défaut pour une prop

Si vous souhaitez donner une valeur par défaut à une prop pour qu’elle l’exploite lorsque le composant parent ne fournit pas de valeur, vous pouvez le faire dans la déstructuration en ajoutant = suivi de la valeur par défaut, juste après le nom de la prop :

function Avatar({ person, size = 100 }) {
// ...
}

À présent, si <Avatar person={...} /> est utilisé sans prop size, la size sera définie à 100.

La valeur par défaut n’est utilisée que si la prop size est manquante ou que vous passez size={undefined}. Mais si vous passez size={null} ou size={0}, la valeur par défaut ne sera pas utilisée.

Transmettre des props avec la syntaxe de spread JSX

Il peut arriver que passer des props soit très répétitif :

function Profile({ person, size, isSepia, thickBorder }) {
return (
<div className="card">
<Avatar
person={person}
size={size}
isSepia={isSepia}
thickBorder={thickBorder}
/>
</div>
);
}

Un tel code répétitif n’est pas problématique en soi — il peut même être plus lisible. Mais vous pourriez préférer la concision. Certains composants refilent toutes leurs props à leurs enfants, comme ce Profile le fait avec Avatar. Dans la mesure où ils n’utilisent pas leurs props directement, il peut être pertinent de recourir à la syntaxe de spread, nettement plus concise :

function Profile(props) {
return (
<div className="card">
<Avatar {...props} />
</div>
);
}

Ça transmet toutes les props de Profile à Avatar sans avoir à les lister chacune par leur nom.

Utilisez la syntaxe de spread avec discernement. Si vous l’utilisez dans de nombreux composants, c’est que quelque chose ne va pas. Le plus souvent, c’est un signe que vous devriez découper vos composants et passer du JSX enfant. On va voir comment tout de suite !

Passer du JSX comme enfant

On imbrique fréquemment les balises natives du navigateur :

<div>
<img />
</div>

Vous voudrez parfois faire de même avec vos propres composants :

<Card>
<Avatar />
</Card>

Lorsque vous imbriquez du contenu dans une balise JSX, le composant parent reçoit ce contenu sous forme d’une prop appelée children. Par exemple, le composant Card ci-dessous recevra une prop children qui vaudra <Avatar /> et l’affichera dans une div d’enrobage :

import Avatar from './Avatar.js';

function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  );
}

export default function Profile() {
  return (
    <Card>
      <Avatar
        size={100}
        person={{
          name: 'Katsuko Saruhashi',
          imageId: 'YfeOqp2'
        }}
      />
    </Card>
  );
}

Tentez de remplacer le <Avatar> au sein de <Card> avec du texte pour constater que le composant Card peut enrober n’importe quel contenu imbriqué. Il n’a pas besoin de « savoir » ce qui est affiché à l’intérieur de lui. Vous retrouverez cette approche flexible dans de nombreux endroits.

Voyez la prop children d’un composant comme une sorte de « trou » qui peut être « rempli » par les composants parents avec du JSX quelconque. Vous utiliserez souvent la prop children pour des enrobages visuels : panneaux, grilles, etc.

Une Card ressemblant à une pièce de puzzle avec un emplacement pour les pièces « enfants » tels que du texte ou un Avatar

Illustré par Rachel Lee Nabors

Les props changent avec le temps

Le composant Clock ci-dessous reçoit deux props de son composant parent : color et time. (Le code du composant parent est laissé de côté parce qu’il utilise un état, concept que nous n’avons pas encore exploré.)

Essayez de modifier la couleur dans la liste déroulante :

export default function Clock({ color, time }) {
  return (
    <h1 style={{ color: color }}>
      {time}
    </h1>
  );
}

Cet exemple illustre le fait qu’un composant peut recevoir des props différentes au fil du temps. Les props ne sont pas toujours figées ! Ici la prop time change à chaque seconde, et la prop color change lorsque vous sélectionnez une autre couleur. Les props reflètent les données du composant à un instant donné, plutôt que seulement leurs valeurs au démarrage.

Cependant, les props sont immuables — un terme qui en informatique signifie « non modifiable ». Lorsqu’un composant a besoin de changer ses props (par exemple, en réponse à une interaction utilisateur ou à de nouvelles données), il doit « demander » à son composant parent de lui passer des props différentes — et donc un nouvel objet ! Ses anciennes props seront alors mises au rebut, et le moteur JavaScript récupèrera à terme la mémoire qui leur était associée.

N’essayez pas de « changer les props ». Lorsque vous aurez besoin de réagir à une interaction utilisateur (telle qu’un changement de la couleur sélectionnée), vous devrez « mettre à jour l’état », ce que vous apprendrez à faire dans L’état : la mémoire d’un composant.

En résumé

  • Pour passer des props, ajoutez-les au JSX, comme pour des attributs HTML.
  • Pour lire des props, utilisez une déstructuration comme dans function Avatar({ person, size }).
  • Vous pouvez spécifier une valeur par défaut comme size = 100, qui sera utilisée si la prop est manquante ou vaut undefined.
  • Vous pouvez transmettre tous les props avec la syntaxe de spread JSX <Avatar {...props} />, mais n’en abusez pas !
  • Le JSX imbriqué dans votre composant, comme dans <Card><Avatar /></Card> est fourni via la prop children du composant Card.
  • Les props sont des instantanés en lecture seule : chaque rendu reçoit une nouvelle version des props.
  • Ne modifiez pas les props. Si vous avez besoin d’interactivité, utilisez l’état.

Défi 1 sur 3 ·
Extraire un composant

Ce composant Gallery contient un balisage très similaire pour deux profils. Extrayez-en un composant Profile pour réduire la duplication. Vous devrez choisir quelles props lui passer.

import { getImageUrl } from './utils.js';

export default function Gallery() {
  return (
    <div>
      <h1>Scientifiques remarquables</h1>
      <section className="profile">
        <h2>Maria Skłodowska-Curie</h2>
        <img
          className="avatar"
          src={getImageUrl('szV5sdG')}
          alt="Maria Skłodowska-Curie"
          width={70}
          height={70}
        />
        <ul>
          <li>
            <b>Profession : </b>
            physicienne et chimiste
          </li>
          <li>
            <b>Récompenses : 4 </b>
            (Prix Nobel de Physique, Prix Nobel de Chimie, Médaille Davy, Médaille Matteucci)
          </li>
          <li>
            <b>A découvert : </b>
            le Polonium (élément)
          </li>
        </ul>
      </section>
      <section className="profile">
        <h2>Katsuko Saruhashi</h2>
        <img
          className="avatar"
          src={getImageUrl('YfeOqp2')}
          alt="Katsuko Saruhashi"
          width={70}
          height={70}
        />
        <ul>
          <li>
            <b>Profession : </b>
            géochimiste
          </li>
          <li>
            <b>Récompenses : 2 </b>
            (Prix Miyake de géochimie, Prix Tanaka)
          </li>
          <li>
            <b>A découvert : </b>
            une méthode de mesure du dioxyde de carbone dans l’eau de mer
          </li>
        </ul>
      </section>
    </div>
  );
}