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

Componenti Funzionali

Cosa Sono i Componenti Funzionali

In React, un componente funzionale è una funzione JavaScript che accetta props come argomento e restituisce JSX. Dal rilascio degli Hooks in React 16.8, i componenti funzionali possono gestire stato e side effects, rendendo i componenti a classe praticamente obsoleti.

// Il componente funzionale più semplice
function Saluto() {
  return <h1>Ciao, mondo!</h1>;
}

Un componente funzionale è valido quando:

  • Il nome inizia con una lettera maiuscola (PascalCase)
  • Restituisce JSX, null, o un tipo renderizzabile da React
  • Accetta un singolo argomento props (opzionale)

Sintassi di Dichiarazione

Esistono diversi modi per dichiarare un componente funzionale.

Function Declaration

function Benvenuto({ nome }) {
  return <h1>Benvenuto, {nome}!</h1>;
}

Arrow Function

const Benvenuto = ({ nome }) => {
  return <h1>Benvenuto, {nome}!</h1>;
};

Arrow Function con Return Implicito

const Benvenuto = ({ nome }) => <h1>Benvenuto, {nome}!</h1>;

// Per JSX multi-linea, usa le parentesi tonde
const Card = ({ titolo, descrizione }) => (
  <div className="card">
    <h2>{titolo}</h2>
    <p>{descrizione}</p>
  </div>
);

Quale Sintassi Scegliere?

La scelta è principalmente stilistica, ma ci sono differenze pratiche:

Caratteristica Function Declaration Arrow Function
Hoisting No
Nome nel DevTools Automatico Serve la variabile
Brevità Media Alta (return implicito)
Consistenza Standard Preferita in molti team

La raccomandazione è scegliere uno stile e mantenerlo coerente in tutto il progetto.

Export dei Componenti

Export Default

Ogni file può avere un solo export default. È lo standard per i componenti principali di un file.

// Dichiarazione e export separati
function PaginaHome() {
  return <h1>Home</h1>;
}
export default PaginaHome;

// Export default inline (function declaration)
export default function PaginaHome() {
  return <h1>Home</h1>;
}

// Import (il nome può essere qualsiasi)
import PaginaHome from "./PaginaHome";
import Home from "./PaginaHome";  // Funziona ugualmente

Named Export

Un file può avere molteplici named export. Utile per esportare componenti secondari o utility.

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

export function CardHeader({ titolo }) {
  return <h2 className="card-header">{titolo}</h2>;
}

export function CardBody({ children }) {
  return <div className="card-body">{children}</div>;
}

// Import (il nome DEVE corrispondere)
import { Card, CardHeader, CardBody } from "./Card";

Re-export con File Index

Un pattern comune è creare file index.ts per raggruppare gli export di una cartella.

// components/ui/index.ts
export { Button } from "./Button";
export { Card, CardHeader, CardBody } from "./Card";
export { Input } from "./Input";
export { Modal } from "./Modal";

// Ora puoi importare tutto da un unico percorso
import { Button, Card, Input, Modal } from "@/components/ui";

Naming Conventions

Nomi dei Componenti

I componenti usano PascalCase, sia per il nome della funzione che per il file.

// CORRETTO
function ProfiloUtente() { ... }
function ListaArticoli() { ... }
function BottonePrimario() { ... }

// SCORRETTO
function profiloUtente() { ... }  // camelCase
function profilo_utente() { ... } // snake_case
function PROFILO() { ... }        // SCREAMING_CASE

Nomi dei File

La convenzione più diffusa è usare PascalCase per i file dei componenti.

components/
├── ProfiloUtente.tsx
├── ListaArticoli.tsx
├── BottonePrimario.tsx
└── ui/
    ├── Button.tsx
    ├── Card.tsx
    └── Input.tsx

Alcuni progetti usano kebab-case per i nomi dei file, che è altrettanto valido purché sia coerente.

components/
├── profilo-utente.tsx
├── lista-articoli.tsx
└── bottone-primario.tsx

Nomi delle Props

Le props usano camelCase, coerentemente con le convenzioni JavaScript.

function Articolo({
  titoloArticolo,
  dataCreazione,
  isPublicato,
  onClickModifica,
  numeroPagine,
}) {
  // ...
}

Organizzazione dei File

Un Componente per File

La regola generale è avere un componente principale per file, con eventuali componenti helper privati nello stesso file.

// ListaProdotti.tsx

// Componente helper privato (non esportato)
function ElementoProdotto({ prodotto }) {
  return (
    <li className="prodotto">
      <span>{prodotto.nome}</span>
      <span>{prodotto.prezzo} EUR</span>
    </li>
  );
}

// Componente principale (esportato)
export default function ListaProdotti({ prodotti }) {
  return (
    <ul>
      {prodotti.map((prodotto) => (
        <ElementoProdotto key={prodotto.id} prodotto={prodotto} />
      ))}
    </ul>
  );
}

Pattern Cartella per Componente

Per componenti complessi, organizza tutto in una cartella dedicata.

ProfiloUtente/
├── ProfiloUtente.tsx        # Componente principale
├── ProfiloUtente.module.css # Stili
├── ProfiloUtente.test.tsx   # Test
├── AvatarProfilo.tsx        # Sotto-componente
├── useProfilo.ts            # Hook personalizzato
├── types.ts                 # Tipi TypeScript
└── index.ts                 # Re-export
// ProfiloUtente/index.ts
export { default } from "./ProfiloUtente";
export type { ProfiloProps } from "./types";

Componenti Puri e Regole

React si aspetta che i componenti siano funzioni pure rispetto alle props: dati gli stessi input, devono restituire lo stesso output.

// CORRETTO: componente puro
function Saluto({ nome }) {
  return <h1>Ciao, {nome}!</h1>;
}

// SCORRETTO: effetto collaterale nel render
function Contatore() {
  let count = 0;
  count++; // Modifica una variabile ad ogni render
  return <p>Conteggio: {count}</p>;
}

// SCORRETTO: modifica le props
function Formattatore({ lista }) {
  lista.sort(); // MAI mutare le props!
  return <ul>{lista.map((item) => <li key={item}>{item}</li>)}</ul>;
}

// CORRETTO: crea una copia prima di modificare
function Formattatore({ lista }) {
  const listaOrdinata = [...lista].sort();
  return <ul>{listaOrdinata.map((item) => <li key={item}>{item}</li>)}</ul>;
}

Componente che Restituisce null

Un componente può restituire null per non renderizzare nulla.

function MessaggioErrore({ errore }) {
  if (!errore) {
    return null;
  }

  return (
    <div className="errore" role="alert">
      <p>{errore}</p>
    </div>
  );
}

Componenti con TypeScript

TypeScript aggiunge sicurezza sui tipi alle props dei componenti.

interface CardProps {
  titolo: string;
  descrizione: string;
  immagine?: string;         // Prop opzionale
  onClick?: () => void;      // Callback opzionale
  variante?: "default" | "evidenziata";
}

function Card({
  titolo,
  descrizione,
  immagine,
  onClick,
  variante = "default",
}: CardProps) {
  return (
    <div className={`card card-${variante}`} onClick={onClick}>
      {immagine && <img src={immagine} alt={titolo} />}
      <h2>{titolo}</h2>
      <p>{descrizione}</p>
    </div>
  );
}

Best Practices

Mantieni i Componenti Piccoli

Se un componente supera le 100-150 righe, probabilmente va suddiviso in componenti più piccoli.

// Troppo grande - suddividi!
function Dashboard() {
  return (
    <div>
      <HeaderDashboard />
      <GraficoVendite />
      <TabellaOrdini />
      <PannelloNotifiche />
    </div>
  );
}

Separa Logica e Presentazione

Estrai la logica complessa in custom hooks, mantenendo i componenti focalizzati sulla presentazione.

// Hook con la logica
function useProdotti() {
  const [prodotti, setProdotti] = useState([]);
  const [caricamento, setCaricamento] = useState(true);

  useEffect(() => {
    fetch("/api/prodotti")
      .then((res) => res.json())
      .then((data) => {
        setProdotti(data);
        setCaricamento(false);
      });
  }, []);

  return { prodotti, caricamento };
}

// Componente focalizzato sulla presentazione
function ListaProdotti() {
  const { prodotti, caricamento } = useProdotti();

  if (caricamento) return <p>Caricamento...</p>;

  return (
    <ul>
      {prodotti.map((p) => (
        <li key={p.id}>{p.nome}</li>
      ))}
    </ul>
  );
}

I componenti funzionali sono il mattone fondamentale di React. Usa PascalCase per i nomi, scegli tra function declaration e arrow function in modo coerente, organizza i file in modo logico e mantieni i componenti piccoli e puri. Il prossimo passo è capire come passare dati tra componenti tramite le props.