00
:
00
:
00
:
00
Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

Props

Cosa Sono le Props

Le props (abbreviazione di “properties”) sono il meccanismo principale per passare dati da un componente genitore a un componente figlio. Funzionano come gli attributi HTML, ma possono trasportare qualsiasi valore JavaScript: stringhe, numeri, oggetti, array, funzioni e persino altri componenti.

// Il genitore passa le props
function App() {
  return <Saluto nome="Marco" eta={28} />;
}

// Il figlio riceve le props come oggetto
function Saluto(props) {
  return (
    <p>Ciao, {props.nome}! Hai {props.eta} anni.</p>
  );
}

Le Props Sono di Sola Lettura

Una regola fondamentale di React: le props sono immutabili. Un componente non deve mai modificare le proprie props.

// SCORRETTO: mai mutare le props
function Componente(props) {
  props.nome = "Altro";  // ERRORE concettuale!
  return <p>{props.nome}</p>;
}

// CORRETTO: usa le props in sola lettura
function Componente(props) {
  return <p>{props.nome}</p>;
}

Questo principio garantisce un flusso di dati unidirezionale (top-down), rendendo l’applicazione più prevedibile e facile da debuggare.

Destructuring delle Props

Il destructuring è il modo più comune e leggibile per accedere alle props.

// Destructuring nei parametri (consigliato)
function ProfiloUtente({ nome, email, ruolo }) {
  return (
    <div className="profilo">
      <h2>{nome}</h2>
      <p>{email}</p>
      <span className="badge">{ruolo}</span>
    </div>
  );
}

// Destructuring nel corpo della funzione
function ProfiloUtente(props) {
  const { nome, email, ruolo } = props;
  return (
    <div className="profilo">
      <h2>{nome}</h2>
      <p>{email}</p>
      <span className="badge">{ruolo}</span>
    </div>
  );
}

Rest Props con Spread

Il pattern rest/spread è utile per passare props rimanenti a un elemento sottostante.

function Pulsante({ variante, children, ...rest }) {
  return (
    <button className={`btn btn-${variante}`} {...rest}>
      {children}
    </button>
  );
}

// Tutte le props extra (onClick, disabled, type, ecc.)
// vengono passate direttamente al <button>
<Pulsante variante="primario" onClick={handleClick} disabled={false} type="submit">
  Invia
</Pulsante>

Tipi di Props

Le props possono trasportare qualsiasi tipo di dato JavaScript.

function EsempioProps({
  // Stringhe
  nome,           // "Marco"

  // Numeri
  eta,            // 28

  // Booleani
  isAttivo,       // true

  // Array
  hobby,          // ["calcio", "lettura"]

  // Oggetti
  indirizzo,      // { citta: "Roma", cap: "00100" }

  // Funzioni (callback)
  onClick,        // () => console.log("click")

  // Componenti React (JSX)
  icona,          // <IconaUtente />

  // Elementi React
  header,         // <h1>Titolo</h1>
}) {
  return <div>{/* ... */}</div>;
}

Passare Props Booleane

Per le props booleane, la sola presenza del nome equivale a true.

// Queste due righe sono equivalenti
<Input disabilitato={true} />
<Input disabilitato />

// Per passare false, devi essere esplicito
<Input disabilitato={false} />

Passare Oggetti e Array

function App() {
  const utente = {
    nome: "Marco",
    email: "marco@example.com",
    hobby: ["calcio", "lettura", "coding"],
  };

  return <ProfiloUtente utente={utente} />;

  // Oppure spread dell'oggetto come props individuali
  // return <ProfiloUtente {...utente} />;
}

function ProfiloUtente({ utente }) {
  return (
    <div>
      <h2>{utente.nome}</h2>
      <p>{utente.email}</p>
      <ul>
        {utente.hobby.map((h) => (
          <li key={h}>{h}</li>
        ))}
      </ul>
    </div>
  );
}

Props con Valori Predefiniti

Puoi assegnare valori di default alle props in diversi modi.

Destructuring con Valori Default

function Pulsante({
  testo = "Click",
  variante = "primario",
  dimensione = "medio",
  disabilitato = false,
}) {
  return (
    <button
      className={`btn btn-${variante} btn-${dimensione}`}
      disabled={disabilitato}
    >
      {testo}
    </button>
  );
}

// Uso senza specificare le props opzionali
<Pulsante />  // Usa tutti i valori default
<Pulsante testo="Invia" variante="secondario" />

defaultProps (Legacy)

defaultProps è un pattern precedente, ancora funzionante ma non più consigliato per i componenti funzionali.

// NON consigliato per componenti funzionali
function Pulsante({ testo, variante }) {
  return <button className={`btn-${variante}`}>{testo}</button>;
}

Pulsante.defaultProps = {
  testo: "Click",
  variante: "primario",
};

Validazione con PropTypes

PropTypes è una libreria che aggiunge controllo dei tipi a runtime per le props. Utile in progetti JavaScript puro (senza TypeScript).

npm install prop-types
import PropTypes from "prop-types";

function Card({ titolo, descrizione, valutazione, tags, onClose }) {
  return (
    <div className="card">
      <button onClick={onClose}>Chiudi</button>
      <h2>{titolo}</h2>
      <p>{descrizione}</p>
      <span>Valutazione: {valutazione}/5</span>
      <div>{tags.join(", ")}</div>
    </div>
  );
}

Card.propTypes = {
  titolo: PropTypes.string.isRequired,
  descrizione: PropTypes.string.isRequired,
  valutazione: PropTypes.number,
  tags: PropTypes.arrayOf(PropTypes.string),
  onClose: PropTypes.func,
};

Card.defaultProps = {
  valutazione: 0,
  tags: [],
};

Tipi PropTypes Disponibili

PropTypes.string           // Stringa
PropTypes.number           // Numero
PropTypes.bool             // Booleano
PropTypes.func             // Funzione
PropTypes.array            // Array
PropTypes.object           // Oggetto
PropTypes.node             // Qualsiasi renderizzabile
PropTypes.element          // Elemento React
PropTypes.instanceOf(Date) // Istanza di una classe
PropTypes.oneOf(["a", "b"]) // Valore tra opzioni specifiche
PropTypes.oneOfType([PropTypes.string, PropTypes.number])
PropTypes.arrayOf(PropTypes.number)   // Array di numeri
PropTypes.shape({                      // Oggetto con forma specifica
  nome: PropTypes.string,
  eta: PropTypes.number,
})

Tipizzazione Props con TypeScript

TypeScript è la soluzione moderna e raccomandata per la tipizzazione delle props. I tipi vengono verificati a compile-time, non a runtime.

Interface per le Props

interface CardProps {
  titolo: string;
  descrizione: string;
  immagine?: string;                    // Opzionale
  valutazione?: number;                 // Opzionale
  variante: "default" | "evidenziata";  // Union type
  tags: string[];                        // Array di stringhe
  autore: {                              // Oggetto tipizzato
    nome: string;
    avatar: string;
  };
  onClose: () => void;                  // Callback senza parametri
  onValuta: (voto: number) => void;     // Callback con parametro
}

function Card({
  titolo,
  descrizione,
  immagine,
  valutazione = 0,
  variante,
  tags,
  autore,
  onClose,
  onValuta,
}: CardProps) {
  return (
    <div className={`card card-${variante}`}>
      <button onClick={onClose}>X</button>
      {immagine && <img src={immagine} alt={titolo} />}
      <h2>{titolo}</h2>
      <p>{descrizione}</p>
      <div>
        <img src={autore.avatar} alt={autore.nome} />
        <span>{autore.nome}</span>
      </div>
    </div>
  );
}

Type vs Interface

// Con type (equivalente per la maggior parte dei casi)
type CardProps = {
  titolo: string;
  descrizione: string;
};

// Con interface (supporta estensione e merging)
interface CardProps {
  titolo: string;
  descrizione: string;
}

// Estensione di interfacce
interface CardConImmagineProps extends CardProps {
  immagine: string;
  altText: string;
}

Pattern di Comunicazione Genitore-Figlio

Callback Props

Le funzioni passate come props permettono ai figli di comunicare con il genitore.

function Genitore() {
  const [messaggi, setMessaggi] = useState<string[]>([]);

  const aggiungiMessaggio = (testo: string) => {
    setMessaggi((prev) => [...prev, testo]);
  };

  return (
    <div>
      <FormMessaggio onInvia={aggiungiMessaggio} />
      <ListaMessaggi messaggi={messaggi} />
    </div>
  );
}

function FormMessaggio({ onInvia }: { onInvia: (testo: string) => void }) {
  const [testo, setTesto] = useState("");

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    onInvia(testo);
    setTesto("");
  };

  return (
    <form onSubmit={handleSubmit}>
      <input value={testo} onChange={(e) => setTesto(e.target.value)} />
      <button type="submit">Invia</button>
    </form>
  );
}

function ListaMessaggi({ messaggi }: { messaggi: string[] }) {
  return (
    <ul>
      {messaggi.map((msg, i) => (
        <li key={i}>{msg}</li>
      ))}
    </ul>
  );
}

Best Practices

  • Usa il destructuring nei parametri per chiarezza
  • Fornisci valori default per le props opzionali
  • Preferisci TypeScript a PropTypes per la tipizzazione
  • Evita lo spread indiscriminato ({...props}) che rende difficile capire quali props vengono passate
  • Nomina le callback props con il prefisso on (es. onClick, onSubmit, onValutazioneChange)
  • Mantieni le props al minimo necessario: se un componente ha troppe props, probabilmente va suddiviso

Le props sono il canale di comunicazione tra componenti React. Scorrono in un’unica direzione (da genitore a figlio), sono immutabili e possono trasportare qualsiasi tipo di dato. Usa il destructuring per leggibilita, TypeScript per la sicurezza dei tipi, e callback props per la comunicazione dal figlio al genitore.