Table of Contents
Una buona organizzazione dei componenti in React ti fa risparmiare tempo, riduce i bug e ti evita refactor continui. Una struttura pensata male, invece, dopo poche settimane inizia a pesare — soprattutto se stai muovendo i primi passi come freelance o come sviluppatore junior. Avevo già parlato di come sia importante l’architettura in un progetto react in questo articolo.
In questo articolo analizziamo gli errori più comuni nella gestione dei componenti React e vediamo come evitarli con soluzioni semplici, concrete e subito applicabili. L’obiettivo è uno solo: aiutarti a costruire un’architettura pulita, scalabile e davvero allineata alle best practice moderne.
Confondere componenti funzionali e classi
Il primo errore nasce ancora prima di parlare di cartelle o architettura: scegliere il tipo di componente sbagliato.
Oggi la linea guida è molto chiara: usa componenti funzionali con gli hook. La documentazione ufficiale di React e gran parte della community si sono ormai spostate in questa direzione, perché i componenti funzionali sono più leggeri, più leggibili e si integrano meglio con l’ecosistema moderno.
Scegliere i componenti di classe, oggi, significa portarsi dietro complessità non necessaria:
- più boilerplate
thisovunque- lifecycle methods da ricordare e gestire
- minore integrazione con hook e pattern moderni
Con i componenti funzionali, invece, stato e side effect si gestiscono in modo molto più diretto tramite useState, useEffect e gli altri hook. La sintassi è più lineare, non devi preoccuparti del binding di this e, nella maggior parte dei casi, scrivi meno codice per ottenere lo stesso risultato.
Se vuoi approfondire davvero le differenze tra i due approcci, può avere senso confrontare in modo strutturato componenti funzionali e componenti di classe. Ma se stai progettando oggi la tua struttura React da zero, considera le classi solo in un caso: quando devi mantenere o estendere codice legacy già esistente.
Mettere tutta la UI in un unico componente gigante
Un altro errore molto comune è concentrare tutto in un unico componente enorme, spesso dentro App.js.
All’inizio può sembrare la strada più veloce, soprattutto se stai lavorando a un progetto piccolo o a un prototipo. Il problema è che quella scelta “comoda” diventa rapidamente un freno. Dopo poche settimane ti ritrovi con:
- centinaia di righe nello stesso file
- logica di stato, chiamate API e JSX mescolati senza una separazione chiara
- difficoltà nel riutilizzare anche un semplice bottone o una card in altre parti dell’app
A quel punto ogni modifica diventa più rischiosa, perché tutto è collegato a tutto.
L’approccio corretto, spiegato molto bene anche nel tutorial ufficiale “Thinking in React” su React.dev, parte invece da una scomposizione dell’interfaccia in parti piccole e riutilizzabili. Prima si ragiona in termini di componenti, poi si costruisce la struttura.
In pratica: se un file inizia a diventare difficile da leggere, è già un segnale che va spezzato. Una buona struttura nasce proprio dalla capacità di dividere responsabilità e rendere ogni componente focalizzato su una sola cosa.
Come spezzare un componente gigante
Quando ti accorgi che un componente sta diventando troppo grande, fermati un attimo e fatti tre domande molto semplici:
- Quali parti dell’interfaccia si ripetono?
- Quali sezioni hanno una responsabilità chiara e ben definita?
- Quali blocchi lavorano sugli stessi dati del tuo modello?
Spesso le risposte ti indicano già dove spezzare.
Un metodo pratico, che funziona sempre, è questo:
- Guarda la UI (o il mockup) con attenzione.
- Disegna mentalmente dei riquadri attorno a ogni sezione logica.
- Dai un nome a ciascun riquadro: quello sarà il tuo prossimo componente.
È esattamente il primo passo del flusso “Thinking in React”: partire dalla struttura visiva per arrivare a quella tecnica.
Anche se il progetto è piccolo, abituarti fin da subito a ragionare per blocchi ti evita refactor pesanti più avanti. Separare le responsabilità all’inizio è molto più semplice che rimettere ordine quando l’app è già cresciuta.
Mettere stato ovunque e duplicare i dati
Un altro errore strutturale molto serio è distribuire lo stato in troppi componenti e, peggio ancora, duplicare le stesse informazioni in più punti dell’app.
Succede spesso in modo quasi invisibile. Per esempio:
- il testo di ricerca salvato in tre componenti diversi
- una lista di prodotti gestita con tre
useStatequasi identici - nessuna chiarezza su chi “possiede” davvero i dati e da dove partono le modifiche
Il risultato? Incoerenze, bug difficili da tracciare e aggiornamenti che non si propagano come dovrebbero.
La documentazione ufficiale di React insiste molto su un principio fondamentale: mantieni lo stato minimo ma completo, e non duplicarlo. Se un’informazione può essere derivata da un’altra, non serve salvarla due volte. Se più componenti hanno bisogno dello stesso dato, quello stato dovrebbe vivere nel loro antenato comune più vicino.
In pratica: meno stato, più controllo. E soprattutto, una sola fonte di verità per ogni informazione importante.
Dove mettere lo stato nel tuo albero di componenti
La regola pratica è molto semplice:
- individua tutti i componenti che usano un certo dato
- risali l’albero fino al loro genitore comune più vicino
- sposta lì lo stato e passalo verso il basso tramite props
Questo è il cuore del pattern della single source of truth. Nel flusso “Thinking in React” viene spiegato proprio nei passaggi centrali: prima individui cosa deve essere stato, poi decidi dove deve vivere.
In concreto, invece di avere:
SearchBarcon il proprio stato di ricercaProductListcon un altro stato di ricerca
crei un componente genitore, ad esempio FilterableProductTable, che possiede lo stato della ricerca. Quel componente:
- passa il valore corrente a
SearchBar - passa il valore filtrato a
ProductList - riceve gli eventi dal basso tramite callback
Il flusso diventa chiaro:
i dati scendono (props), gli eventi salgono (callback).
È una scelta semplice, ma quando l’app cresce fa una differenza enorme. Avere una sola fonte di verità rende il comportamento prevedibile, riduce i bug e mantiene la struttura dei componenti ordinata e scalabile.
Usare ereditarietà invece di composizione
Se arrivi da Java o C#, l’istinto iniziale è spesso: “Creo una classe base BaseComponent e la estendo”. In React questo approccio è quasi sempre un errore.
La documentazione stessa sconsiglia l’ereditarietà per i componenti e suggerisce di usare la composizione (React Legacy Docs).
Con la composizione:
- crei componenti generici, ad esempio
Dialog - li specializzi passando
propse figli, ad esempioWelcomeDialog - eviti gerarchie di classi difficili da mantenere
L’esempio classico:
function Dialog({ title, message, children }) {
return (
<div className="dialog">
<h1>{title}</h1>
<p>{message}</p>
{children}
</dSe arrivi da Java o C#, l’istinto iniziale è spesso: “Creo una classe base BaseComponent e la estendo”. In React questo approccio è quasi sempre un erroretiv>
);
}
function WelcomeDialog() {
return (
<Dialog title="Benvenuto" message="Grazie per esserti registrato">
<button>Inizia</button>
</Dialog>
);
}
Lascia perdere l’ereditarietà. In React funziona molto meglio avere un unico componente riutilizzabile e creare le varianti semplicemente configurandolo tramite props.
Invece di costruire gerarchie complesse, rendi il componente flessibile: cambi comportamento, stile o contenuto passando proprietà diverse. È un approccio semplice, ma estremamente potente — ed è lo stesso modello usato in migliaia di componenti reali in produzione, anche all’interno di Facebook.
Se vuoi fare un passo in più e capire come strutturare davvero bene un progetto, può essere utile approfondire i principali pattern di architettura in React. Conoscere questi schemi ti aiuta a prendere decisioni più consapevoli fin dall’inizio e a costruire basi solide per quando l’app inizierà a crescere.
Scrivere componenti rigidi e non riutilizzabili
C’è un errore che, da freelance, si paga quasi subito: creare componenti talmente specifici da essere inutilizzabili fuori da quel progetto.
Magari funzionano benissimo lì dentro, ma appena inizi un nuovo lavoro ti accorgi che non puoi riusarli senza modificarli pesantemente. E ogni volta riparti quasi da zero.
Se vuoi che la tua struttura React sia davvero un investimento e non solo codice “usa e getta”, ogni componente riutilizzabile dovrebbe essere:
- configurabile tramite props
- separato dalla logica di business troppo specifica
- il più possibile “stupido”, cioè focalizzato solo sulla UI
Un buon componente riutilizzabile non deve sapere perché viene usato, ma solo come deve mostrarsi e comportarsi in base alle proprietà che riceve.
Le guide pratiche sui componenti riutilizzabili insistono proprio su questo: le props sono il meccanismo chiave per personalizzare comportamento e aspetto, dal bottone più semplice fino a una Navbar complessa. Più il componente è generico e configurabile, più valore avrà nel tempo — soprattutto se lavori su progetti diversi.
Esempio: da bottone rigido a bottone riutilizzabile
Ecco la differenza concreta tra un componente rigido e uno davvero riutilizzabile.
Versione rigida:
function SubmitButton() {
return <button className="btn btn-primary">Invia</button>;
}
Funziona. Ma fa solo una cosa, in un solo modo. Se ti serve un bottone “Annulla” o “Elimina”, devi crearne un altro. E poi un altro ancora.
Versione riutilizzabile:
function Button({ label, variant = "primary", onClick }) {
return (
<button className={`btn btn-${variant}`} onClick={onClick}>
{label}
</button>
);
}
Qui il componente è lo stesso, ma diventa flessibile.
Puoi usarlo così:
- per “Invia”
- per “Annulla”
- per “Elimina”
- per qualsiasi altra azione
Cambi solo le props, non la struttura.
È esattamente lo stesso principio applicato a componenti più complessi, come una Navbar: invece di codificare tutto al suo interno, passi dall’esterno parametri come isLoggedIn, le voci di menu o i callback delle azioni.
Il risultato? Meno duplicazione, più coerenza e una base di componenti che puoi portarti dietro progetto dopo progetto.
Mettere API call e side effect dentro ogni componente
Un altro errore strutturale molto comune è inserire chiamate API e side effect direttamente dentro i componenti di presentazione, magari ripetendo la stessa logica in più punti dell’app.
All’inizio può sembrare pratico. Poi iniziano i problemi:
- fai la stessa
fetchin tre componenti diversi - non puoi riusare il componente senza portarti dietro anche la chiamata API
- testare la UI diventa complicato, perché dipende sempre dalla rete
Il componente smette di essere un semplice blocco visivo e diventa un pezzo accoppiato alla logica di recupero dati. E questo lo rende fragile.
Un principio sano è questo: più un componente è pensato per essere riutilizzato, meno dovrebbe sapere da dove arrivano i dati.
Idealmente, il componente di presentazione riceve tutto tramite props e si limita a renderizzare. La logica di fetch, trasformazione dati e gestione degli effetti collaterali dovrebbe vivere più in alto (in un container, in un custom hook o in un livello di servizio separato).
Separare responsabilità in questo modo ti dà tre vantaggi concreti:
- componenti più puliti
- riuso reale tra progetti
- test molto più semplici
In sostanza: la UI mostra, la logica decide. Mischiare le due cose è uno dei modi più rapidi per complicare una struttura React che potrebbe essere molto più lineare.
Separare smart e dumb component
Un pattern molto semplice — ma estremamente efficace — è dividere i componenti in due categorie:
- componenti “smart” (o container): gestiscono stato, chiamate API e logica
- componenti “dumb” (o presentational): ricevono dati già pronti via props e si occupano solo della UI
Vediamo un esempio concreto.
function UsersContainer() {
const [users, setUsers] = useState([]); useEffect(() => {
fetch("/api/users")
.then(res => res.json())
.then(setUsers);
}, []); return <UserList users={users} />;
}
Qui UsersContainer si occupa di recuperare i dati e gestire lo stato.
function UserList({ users }) {
return (
<ul>
{users.map(u => <li key={u.id}>{u.name}</li>)}
</ul>
);
}
UserList, invece, non sa nulla di API o fetch. Riceve un array e lo mostra. Punto.
Il risultato è molto potente:
UserListè altamente riutilizzabile- puoi testarlo facilmente passando un array finto
- puoi cambiare la fonte dei dati senza toccare la UI
Il container orchestra, il presentational renderizza.
Separare questi due ruoli rende la struttura più chiara, più modulare e molto più facile da far crescere nel tempo.
Organizzare i file senza criterio
La struttura dei componenti in React non riguarda solo la logica, ma anche l’organizzazione di file e cartelle. Uno degli errori più comuni è lasciare tutto dentro src/ o components/ senza un criterio preciso.
All’inizio sembra innocuo. Con il tempo, però:
- diventa difficile trovare il componente giusto
- iniziano a comparire nomi duplicati o poco chiari
- non è più evidente cosa sia davvero riutilizzabile e cosa appartenga a una singola feature
Una buona struttura non nasce perfetta fin da subito: evolve insieme al progetto. Un approccio graduale, suggerito anche da sviluppatori esperti come Robin Wieruch, può essere questo:
🔹 Progetti piccoli
Puoi partire tranquillamente con pochi file, magari anche tutto dentro App.js. Quando un blocco cresce troppo, lo estrai in un file dedicato. L’importante è intervenire appena il codice diventa difficile da leggere.
🔹 Progetti medi
Inizia a raggruppare i componenti in una cartella components/.
Puoi organizzare per gruppi logici: ad esempio List.js che contiene sia List sia ListItem, esportando solo ciò che serve davvero all’esterno.
Questo aiuta a mantenere ordine senza complicare troppo la struttura.
🔹 Progetti più grandi
Qui conviene fare un passo in più: una cartella per ogni componente.
Esempio:
Button/
Button.jsx
Button.module.css
Button.test.js
index.js
index.js diventa la “porta d’ingresso” del componente.
In parallelo, inizi a separare le responsabilità creando cartelle come:
hooks/per la logica riutilizzabilecontext/per lo stato globaleservices/per API e funzioni di accesso ai dati
La UI resta separata dalla logica condivisa.
🔹 Applicazioni molto grandi
Qui il salto è organizzare per feature, non per tipo di file.
Esempio:
auth/
posts/
payments/
Ogni feature contiene i propri componenti, hook e servizi.
I componenti davvero generici e riutilizzabili vivono invece in una cartella components/ condivisa.
Questa evoluzione naturale ti permette di far crescere l’app senza dover ristrutturare tutto ogni sei mesi.
Una regola pratica molto semplice:
se fai fatica a intuire dove si trova un componente, probabilmente la struttura delle cartelle ha bisogno di essere rivista.
Organizzare bene oggi significa risparmiare tempo (e frustrazione) domani.
Ignorare children e composizione avanzata
Infine, c’è un errore che riduce parecchio la flessibilità dei tuoi componenti: non sfruttare children e la composizione “a buchi multipli”.
React ti permette di passare contenuto direttamente dentro un componente tramite props.children. È un meccanismo semplice, ma potentissimo — perfetto per layout come Sidebar, Dialog, PageLayout e strutture simili.
Esempio base:
function Card({ children }) {
return <div className="card">{children}</div>;
}// Uso
<Card>
<h2>Profilo</h2>
<p>Dettagli utente...</p>
</Card>
Qui Card non sa nulla del contenuto che renderizzerà. Si limita a fornire la struttura. Il contenuto viene deciso dall’esterno. Questo rende il componente estremamente riutilizzabile.
Ma puoi fare anche di più.
Oltre a children, puoi creare veri e propri “slot multipli” passando JSX come altre props, ad esempio:
<PageLayout
header={<Header />}
sidebar={<Sidebar />}
footer={<Footer />}
>
<MainContent />
</PageLayout>
In questo modo il componente diventa un contenitore flessibile, capace di accogliere blocchi diversi in posizioni diverse. È l’equivalente degli “slot” presenti in altri framework, ma senza limiti particolari su cosa puoi passare: qualsiasi JSX è valido.
Sfruttare bene children e la composizione ti permette di costruire layout potenti senza ricorrere a gerarchie complesse o a componenti rigidi. È uno di quei dettagli che, quando impari a usarlo davvero, cambia completamente il modo in cui progetti la tua struttura React.

Commenti recenti