Passare Props ad un Componente

I componenti React utilizzano le props per comunicare tra loro. Ogni componente genitore può passare alcune informazioni ai suoi componenti figli passandogli le props. Le props potrebbero ricordarti gli attributi HTML, ma attraverso di esse puoi passare qualsiasi valore JavaScript, inclusi oggetti, array e funzioni.

Imparerai

  • Come passare props ad un componente
  • Come leggere props da un componente
  • Come specificare valori di default per le props
  • Come passare del JSX ad un componente
  • Come cambiano le props nel tempo

Props familiari

Le props sono le informazioni che passi ad un tag JSX. Ad esempio, className, src, alt, width e height sono alcune delle props che puoi passare ad un <img>:

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 />
  );
}

Le props che puoi passare ad un tag <img> sono predefinite (ReactDOM si conforma allo standard HTML). Ma puoi passare qualsiasi props ai tuoi componenti, come <Avatar>, per personalizzarli. Ecco come!

Passare props ad un componente

In questo codice, il componente Profile non sta passando alcuna props al suo componente figlio, Avatar:

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

Puoi dare ad Avatar delle props in due passaggi.

Step 1: Passa le props al componente figlio

Prima di tutto, passa alcune props ad Avatar. Ad esempio, passiamo due props: person (un oggetto) e size (un numero):

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

Nota

Se le doppie graffe dopo person= ti confondono, ricorda che sono semplicemente un oggetto all’interno delle graffe JSX.

Adesso puoi leggere queste props all’interno del componente Avatar.

Step 2: Leggi le props all’interno del componente figlio

Puoi leggere queste props elencando i loro nomi person, size separati da virgole all’interno di ({ e }) direttamente dopo function Avatar. Questo ti permette di usarle all’interno del codice di Avatar, come faresti con una variabile.

function Avatar({ person, size }) {
// person e size sono disponibili qui
}

Aggiungi della logica ad Avatar che usa le props person e size per il rendering, ed è fatta.

Adesso puoi configurare Avatar per farlo renderizzare in molti modi diversi con props diverse. Prova a modificare i valori!

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>
  );
}

Le props ti fanno pensare ai componenti genitori e figli in maniera indipendente. Ad esempio, puoi cambiare le props person o size all’interno di Profile senza dover pensare a come Avatar le utilizza. In maniera simile, puoi cambiare come Avatar usa queste props, senza guardare Profile.

Puoi pensare alle props come a delle “rotelle” che puoi regolare. Servono allo stesso scopo degli argomenti per le funzioni-infatti, le props sono l’unico argomento per il tuo componente! Le funzioni dei componenti React accettano un singolo argomento, un oggetto props:

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

Solitamente non hai bisogno dell’intero oggetto props in sé, quindi lo destrutturi in props individuali.

Insidia

Non dimenticare la coppia di graffe { e } all’interno di ( e ) quando dichiari le props:

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

Questa sintassi è chiamata “destructuring” ed è equivalente a leggere le proprietà da un parametro di una funzione:

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

Specificare un valore di default per una prop

Se vuoi dare a una prop un valore di default da utilizzare quando non viene specificato alcun valore, puoi farlo tramite il destructuring mettendo = ed il valore di default subito dopo il parametro:

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

Adesso, se <Avatar person={...} /> viene renderizzato senza la prop size, il size verrà impostato a 100.

Il valore di default è utilizzato solo se la prop è mancante o se passi size={undefined}. Ma se passi size={null} o size={0}, il valore di default non verrà utilizzato.

Inoltrare props con la sintassi di spread JSX

Qualche volta, passare le props diventa molto ripetitivo:

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

Non c’è nulla di sbagliato nel codice ripetitivo-può essere più leggibile. Ma a volte puoi preferire la concisione. Alcuni componenti inoltrano tutte le loro props ai loro figli, come fa questo Profile con Avatar. Poiché non utilizzano direttamente nessuna delle loro props, può avere senso utilizzare una sintassi più concisa, chiamata “spread”:

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

Questo inoltra tutte le props di Profile all’Avatar senza elencare i loro nomi.

Utilizza la sintassi di spread con moderazione. Se la utilizzi in ogni componente, probabilmente c’è qualcosa che non va. Spesso, questo indica che dovresti suddividere i tuoi componenti e passare i figli come JSX. Ne parleremo dopo!

Passare JSX come figlio

È comune annidare tag del browser incorporati:

<div>
<img />
</div>

Qualche volta vorrai annidare i tuoi componenti allo stesso modo:

<Card>
<Avatar />
</Card>

Quando annidi del contenuto all’interno di un tag JSX, il componente genitore riceverà quel contenuto in una prop chiamata children. Ad esempio, il componente Card qui sotto riceverà una prop children impostata ad <Avatar /> e la renderizzerà in un div contenitore:

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>
  );
}

Prova a sostituire l’<Avatar> all’interno di <Card> con del testo per vedere come il componente Card può avvolgere qualsiasi contenuto annidato. Non ha bisogno di “sapere” cosa viene renderizzato al suo interno. Vedrai questo modello flessibile in molti punti.

Puoi pensare a un componente con una prop children come ad avere un “buco” che può essere “riempito” dai suoi componenti genitori con JSX arbitrario. Spesso utilizzerai la prop children per i contenitori visivi: pannelli, griglie, ecc.

Una tessera Card a forma di puzzle con uno slot per i pezzi "children" come testo e Avatar

Illustrato da Rachel Lee Nabors

Come cambiano le props nel tempo

Il componente Clock qui sotto riceve due props dal suo componente genitore: color e time. (Il codice del componente genitore viene omesso perché utilizza state, che al momento non approfondiremo ancora.)

Prova a cambiare il colore nella casella di selezione qui sotto:

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

Questo esempio illustra che un componente può ricevere props diverse nel tempo. Le props non sono sempre statiche! Qui, la prop time cambia ogni secondo e la prop color cambia quando selezioni un altro colore. Le props riflettono i dati di un componente in un determinato momento, invece che solo all’inizio.

Tuttavia, le props sono immutabili—un termine della scienza informatica che significa “non modificabile”. Quando un componente ha bisogno di cambiare le sue props (ad esempio, in risposta a un’interazione dell’utente o a nuovi dati), dovrà “chiedere” al suo componente genitore di passargli props diverse—un nuovo oggetto! Le sue vecchie props verranno quindi scartate ed alla fine il motore JavaScript reclamerà la memoria occupata da esse.

Non provare a “cambiare le props”. Quando hai bisogno di rispondere all’input dell’utente (come cambiare il colore selezionato), dovrai “impostare lo state”, che puoi imparare in State: La Memoria di un Componente.

Riepilogo

  • Per passare le props, aggiungile al JSX, proprio come faresti con gli attributi HTML.
  • Per leggere le props, usa la sintassi di destrutturazione function Avatar({ person, size }).
  • Puoi specificare un valore predefinito come size = 100, che viene utilizzato per le props mancanti ed undefined.
  • Puoi inoltrare tutte le props con la sintassi di spread JSX <Avatar {...props} />, ma non abusarne!
  • Il JSX annidato come <Card><Avatar /></Card> apparirà come children della prop del componente Card.
  • Le props sono istantanee di sola lettura nel tempo: ogni render riceve una nuova versione delle props.
  • Non puoi cambiare le props. Quando hai bisogno di interattività, dovrai impostare lo state.

Sfida 1 di 3:
Estrarre un componente

Questo componente Gallery contiene alcuni markup molto simili per due profili. Estrai un componente Profile da esso per ridurre la duplicazione. Dovrai scegliere quali props passargli.

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

export default function Gallery() {
  return (
    <div>
      <h1>Notable Scientists</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> 
            physicist and chemist
          </li>
          <li>
            <b>Awards: 4 </b> 
            (Nobel Prize in Physics, Nobel Prize in Chemistry, Davy Medal, Matteucci Medal)
          </li>
          <li>
            <b>Discovered: </b>
            polonium (element)
          </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> 
            geochemist
          </li>
          <li>
            <b>Awards: 2 </b> 
            (Miyake Prize for geochemistry, Tanaka Prize)
          </li>
          <li>
            <b>Discovered: </b>
            a method for measuring carbon dioxide in seawater
          </li>
        </ul>
      </section>
    </div>
  );
}