Quando si parla di architettura React, quasi tutti i problemi nascono da un errore di partenza:
👉 organizzare il progetto React copiando modelli mentali che non gli appartengono.
Cartelle controllers, models, views.
Oppure separazioni forzate per “tipo di file”.
O peggio: una struttura che cresce per imitazione, non per necessità.
Il risultato è sempre lo stesso:
- codice frammentato
- responsabilità confuse
- onboarding lento
- refactor costosi
Il problema non è la struttura in sé.
È il criterio con cui la scegli.
In breve: React non è MVC e non impone una struttura. Un progetto React regge nel tempo quando lo organizzi per feature e responsabilità, tieni lo stato vicino a chi lo usa e lasci che la UI sia una funzione dello stato.
In questa guida:
- Perché React non è MVC
- React non ha Controller
- Il flusso unidirezionale
- Come strutturare un progetto React
- Separare per tipo o per dominio
- Dove mettere lo stato
- Conclusione

Perché React non è MVC
Uno degli errori più comuni (e più costosi) quando si lavora con React è cercare di incastrarlo dentro il modello MVC.
Succede quasi sempre a chi:
- viene da backend tradizionale
- ha studiato architetture “classiche”
- cerca ordine replicando schemi già conosciuti
Il risultato è prevedibile:
- componenti che fanno troppe cose
- stato sparso
- logica difficile da seguire
- refactor dolorosi
👉 Il problema non è React.
👉 Il problema è forzare un modello che React non è.
Perché MVC è così difficile da abbandonare
MVC (Model–View–Controller) ha funzionato bene per anni perché risolveva un problema preciso:
separare responsabilità in sistemi server-centrici
Ma React nasce per un contesto diverso:
- UI dinamiche
- stato che cambia spesso
- rendering reattivo
- flussi asincroni continui
Applicare MVC a React è come usare una mappa di carta per guidare un drone:
ti dà l’illusione di controllo, ma non descrive il sistema che stai usando.
React non ha Controller (e questo manda in crisi)
Nel modello MVC:
- il Model gestisce i dati
- il View mostra
- il Controller coordina
In React:
- non esiste un controller centrale
- non c’è un punto unico che “decide cosa fare”
- la UI è una funzione dello stato
Questo è il cuore del modello dichiarativo di React, spiegato chiaramente anche nella documentazione ufficiale quando si introduce il concetto di pensare in React.
Tu non dici:
“quando succede X, fai Y”
Dici:
“se lo stato è X, la UI è Y”
È una differenza sottile, ma devastante se la ignori.
Il danno più comune: componenti-controller mascherati
Quando tratti React come MVC, succede questo:
- nascono componenti enormi
- pieni di logica decisionale
- che orchestrano tutto
Sono controller travestiti da componenti.
Segnali tipici:
ifannidati ovunque- stato che governa mezzo albero
- side effect gestiti “per far funzionare le cose”
- difficoltà a testare
Questi componenti diventano colli di bottiglia.
Ogni modifica è rischiosa. Ogni bug è difficile da isolare.
In React il flusso è unidirezionale (e questo cambia tutto)
Un altro punto di rottura con MVC è il flusso dei dati.
In React:
- i dati scendono
- le azioni risalgono
- lo stato guida il rendering
Questo flusso unidirezionale è uno dei principi fondamentali del framework ed è alla base della sua prevedibilità, come spiegato anche nella panoramica MDN su React e sulla gestione dello stato.
MVC invece:
- prevede più direzioni
- più punti di coordinamento
- più accoppiamento implicito
Se cerchi di replicare questo schema in React, stai combattendo il framework.
React non è MVC. È composizione + stato + dichiaratività
Un modello mentale più corretto per React è questo:
- Componenti → funzioni di rendering
- Stato → fonte di verità
- Composizione → modo di costruire UI complesse
- Eventi → segnali che richiedono cambiamento
Non c’è un controller che coordina tutto.
C’è uno stato che determina cosa esiste.
Quando accetti questo:
- i componenti diventano più piccoli
- la logica si distribuisce
- il codice è più leggibile
Il vero criterio: cosa cambia nel tempo
Se vuoi un principio pratico che funziona meglio di MVC, usa questo:
Se qualcosa cambia nel tempo, è stato.
Se qualcosa reagisce al cambiamento, è rendering.
Se qualcosa descrive come combinare parti, è composizione.
Questo ti evita:
- controller centrali
- logica duplicata
- dipendenze nascoste
Ed è perfettamente allineato con il modo in cui React è stato progettato.
Smettere di cercare MVC è un atto di maturità
React non è MVC.
Non lo diventerà.
E non è un limite.
È un framework pensato per:
- interfacce dinamiche
- flussi complessi
- cambiamento continuo
Continuare a trattarlo come MVC significa:
- rallentare
- complicare
- perdere i benefici reali
Quando smetti di cercare controller e inizi a modellare lo stato e le responsabilità, React diventa finalmente leggibile.
Non perché è semplice.
Ma perché stai usando il modello giusto.
A questo punto il passo naturale è capire come organizzare un progetto React senza cadere in cartelle MVC travestite.
Come strutturare un progetto React
React non chiede una struttura “giusta”. Chiede una struttura coerente
Una verità scomoda:
React non impone un’architettura.
Ed è proprio questo che manda in crisi.
Chi viene da framework opinionati cerca:
- regole rigide
- cartelle standard
- pattern “ufficiali”
React invece ti chiede di fare una cosa più difficile:
👉 pensare in termini di responsabilità e cambiamento nel tempo.
Questo approccio è coerente con quanto spiegato nella documentazione ufficiale quando React parla di composizione e separazione logica, non di layer architetturali fissi (vedi Thinking in React su react.dev).
L’errore più comune: separare per “tipo” invece che per “dominio”
Struttura tipica sbagliata:
components/
hooks/
services/
utils/
pages/
Sembra ordinata.
Ma nasconde un problema serio: la logica di una feature è sparsa ovunque.
Per capire come funziona una singola funzionalità devi:
- saltare tra cartelle
- tenere tutto in testa
- ricostruire il flusso
Questa non è architettura.
È frammentazione.
Chi ragiona in MVC tende a forzare:
- cartelle
controllers - cartelle
models - cartelle
views
In React questo spesso produce:
- frammentazione artificiale
- passaggi inutili
- più boilerplate
React non chiede di separare per tipo.
Chiede di separare per responsabilità.
Un criterio migliore: separare per responsabilità funzionale
In React funziona meglio un approccio feature-oriented.
Non separi per “cos’è” un file.
Separi per cosa fa nel dominio dell’app.
Esempio concettuale:
features/
auth/
AuthForm.jsx
useAuth.js
authService.js
profile/
ProfileView.jsx
useProfile.js
profileService.js
Qui:
- tutto ciò che cambia insieme sta insieme
- la logica è localizzata
- l’impatto di una modifica è prevedibile
Questo modello riduce:
- accoppiamento
- dipendenze nascoste
- paura del refactor
I componenti non sono “view”: sono unità di comportamento
Altro errore mentale:
“Questo è un componente di presentazione, questo è logica.”
In React questa distinzione è spesso artificiale.
Un componente può:
- gestire stato
- reagire a eventi
- renderizzare UI
E va bene così.
Forzare separazioni premature crea:
- wrapper inutili
- prop drilling
- componenti fantasma
React non ti chiede purezza architetturale.
Ti chiede chiarezza.
Dove mettere lo stato (e dove NO)
Una struttura sana riflette ciò che abbiamo già chiarito sullo stato:
- stato locale → vicino a chi lo usa
- stato condiviso → sale solo quando serve
- stato globale → raro e intenzionale
Se la struttura ti obbliga a:
- spostare stato “perché la cartella lo impone”
- centralizzare tutto “per ordine”
stai facendo architettura contro React, non con React.
Attenzione ai “framework mentali importati”
Alcuni segnali che stai importando modelli sbagliati:
- cartelle MVC in un progetto React
- servizi che “decidono cosa fare”
- componenti passivi che aspettano istruzioni
- logica nascosta fuori dal flusso di rendering
React funziona meglio quando:
- le decisioni emergono dallo stato
- il rendering è conseguenza, non comando
- la struttura segue il dominio, non la tecnologia
Questo è coerente anche con le linee guida MDN su React, dove il focus è sempre su flusso dei dati e responsabilità, non su layer architetturali rigidi.
Una struttura “giusta” è quella che regge il cambiamento
La domanda corretta non è:
“Questa struttura è elegante?”
Ma:
“Quando cambierà questa feature, quante cose dovrò toccare?”
Se la risposta è:
- “poche, e so dove” → stai facendo bene
- “dipende, devo cercare” → stai accumulando debito
Una buona architettura React:
- non impressiona
- non è accademica
- sopravvive al cambiamento
Conclusione: l’architettura non è una cartella, è una decisione continua
React non ti dà un’architettura perché:
- ogni app è diversa
- ogni dominio ha priorità diverse
- ogni team evolve
Ma ti dà un modello chiaro:
- stato come fonte di verità
- composizione come strumento
- flusso unidirezionale come garanzia
Se costruisci la struttura seguendo questi principi,
non avrai bisogno di “pattern salvifici”.
Avrai un progetto:
- leggibile
- manutenibile
- onesto
E questo, nel tempo, vale più di qualunque struttura “perfetta”.
Questo articolo è collegato a:
- 👉 React per chi viene da HTML e CSS: l’errore mentale che ti sta rallentando
- 👉 React: come progettare componenti senza pensare in HTML
- 👉 React: come gestire lo stato senza creare caos
- 👉 React Hooks: quali servono davvero (e quali puoi ignorare)
- 👉 React: architettura, stato e componenti (percorso completo)
- 👉 Architettura frontend e modelli mentali







