Introduzione a React: Perché è così popolare e come ti cambia la vita di sviluppatore
Benvenuti nel mondo entusiasmante dello sviluppo web moderno! Se sei qui, probabilmente hai già sentito parlare di React, o React.js. Ma cos'è esattamente? React è una libreria JavaScript open-source per la costruzione di interfacce utente (UI) interattive e dinamiche. È stata sviluppata da Facebook (ora Meta) e rilasciata nel 2013, diventando rapidamente uno degli strumenti più amati e utilizzati dagli sviluppatori frontend di tutto il mondo.
Cos'è React e perché dovresti usarlo?
La prima cosa da capire è che React è una libreria, non un framework completo. Questo significa che si concentra principalmente sulla "V" di MVC (Model-View-Controller), ovvero sulla visualizzazione dell'interfaccia utente. A differenza di un framework come Angular che offre una soluzione "all-in-one" con un'architettura predefinita, React ti dà più libertà su come strutturare il resto della tua applicazione (routing, gestione dello stato, fetching dati, ecc.).
Ma perché React è così popolare e perché dovresti impararlo?
- Approccio basato sui Componenti: React ti incoraggia a costruire la tua UI come un insieme di componenti isolati, riutilizzabili e indipendenti. Pensa a un componente come a un piccolo blocco Lego: puoi costruire un bottone, una barra di navigazione, una card prodotto, e poi combinarli per creare interfacce complesse. Questo approccio rende il codice più modulare, facile da gestire e da testare.
- Virtual DOM: Questa è una delle caratteristiche chiave che rende React così performante. Invece di manipolare direttamente il DOM (Document Object Model) del browser, che può essere lento, React crea una copia leggera del DOM in memoria, chiamata Virtual DOM. Quando lo stato dell'applicazione cambia, React confronta il Virtual DOM attuale con quello precedente, calcola le differenze e aggiorna solo le parti del DOM reale che sono effettivamente cambiate. Questo processo, chiamato "riconciliazione", minimizza le operazioni sul DOM reale, rendendo le applicazioni incredibilmente veloci e reattive.
- JSX (JavaScript XML): È una sintassi estensione per JavaScript che ti permette di scrivere codice simile all'HTML direttamente all'interno dei tuoi file JavaScript. Sembra strano all'inizio, ma rende la scrittura di componenti UI molto più intuitiva e leggibile, combinando la logica di visualizzazione con la logica del componente stesso.
- Grande Comunità e Ecosistema: Essendo una delle librerie più diffuse, React vanta una comunità enorme e attiva. Questo significa che troverai facilmente risorse, tutorial, risposte ai problemi e un'ampia gamma di librerie e strumenti di terze parti per estendere le funzionalità della tua applicazione.
- Performance e Scalabilità: Grazie al Virtual DOM e all'ottimizzazione del rendering, le applicazioni React sono intrinsecamente performanti. L'approccio a componenti le rende anche altamente scalabili, permettendo di gestire progetti di qualsiasi dimensione con maggiore facilità.
In questa guida, ti accompagneremo passo dopo passo attraverso i concetti fondamentali di React, partendo dalla configurazione dell'ambiente fino alla creazione di una piccola applicazione interattiva. Preparati a scoprire un modo potente ed efficiente per costruire interfacce utente moderne!
Preparazione dell'Ambiente di Sviluppo: Il tuo laboratorio React
Prima di poter scrivere la tua prima riga di codice React, è necessario configurare l'ambiente di sviluppo. Non preoccuparti, il processo è piuttosto semplice e ti permetterà di avviare rapidamente un nuovo progetto.
Node.js e npm/yarn: i tuoi alleati
React è una libreria JavaScript, e per sviluppare applicazioni React avrai bisogno di Node.js. Node.js è un runtime JavaScript che ti permette di eseguire codice JavaScript al di fuori del browser. Ma perché ci serve per React?
- npm (Node Package Manager) o Yarn: Quando installi Node.js, viene installato anche npm (o puoi installare Yarn separatamente). Questi sono gestori di pacchetti che ti permettono di scaricare e gestire tutte le dipendenze (librerie, strumenti, ecc.) necessarie per il tuo progetto React. React stesso e tutte le sue dipendenze sono pacchetti npm/yarn.
- Strumenti di build: I progetti React moderni utilizzano strumenti come Webpack e Babel per compilare il codice JSX in JavaScript standard che i browser possono capire, e per raggruppare tutti i file in un bundle ottimizzato. Questi strumenti vengono eseguiti tramite Node.js.
Installazione di Node.js
-
Visita il sito ufficiale: Vai su nodejs.org.
-
Scarica la versione LTS: Ti consigliamo di scaricare la versione LTS (Long Term Support), che è la più stabile e raccomandata per la maggior parte degli utenti. Segui le istruzioni di installazione per il tuo sistema operativo (Windows, macOS, Linux).
-
Verifica l'installazione: Dopo l'installazione, apri il tuo terminale o prompt dei comandi ed esegui questi comandi per verificare che Node.js e npm siano stati installati correttamente:
node -v npm -vDovresti vedere i numeri di versione di Node.js e npm. Se vuoi usare Yarn (un'alternativa più veloce a npm), puoi installarlo con
npm install -g yarne poi verificare conyarn -v.
Create React App (CRA): il modo più semplice per iniziare
Configurare un progetto React da zero con tutti gli strumenti di build (Webpack, Babel, ecc.) può essere complesso per i principianti. Fortunatamente, esiste uno strumento fantastico chiamato Create React App (CRA). CRA è un toolkit ufficiale mantenuto da Facebook che ti permette di creare un nuovo progetto React con una configurazione di sviluppo moderna e pronta all'uso, senza dover configurare manualmente nulla. Pensalo come un "generatore di progetti React" che ti fornisce una base solida su cui costruire.
Creare il tuo primo progetto React con CRA
-
Apri il terminale: Naviga nella cartella in cui desideri creare il tuo progetto.
-
Crea una nuova app React: Esegui il seguente comando nel terminale:
npx create-react-app il-mio-primo-progetto-reactnpxè un tool che ti permette di eseguire pacchetti npm senza installarli globalmente. In questo caso, eseguecreate-react-app.il-mio-primo-progetto-reactsarà il nome della tua cartella di progetto. Puoi scegliere qualsiasi nome tu voglia (solo minuscole, numeri e trattini).
Questo comando creerà una nuova directory con il nome specificato, scaricherà tutte le dipendenze necessarie e configurerà la tua applicazione React.
-
Naviga nella directory del progetto: Una volta completato il processo (potrebbe volerci qualche minuto), entra nella cartella del tuo progetto:
cd il-mio-primo-progetto-react -
Avvia l'applicazione: Esegui il comando per avviare il server di sviluppo:
npm starto, se usi Yarn:
yarn startQuesto aprirà automaticamente il tuo browser all'indirizzo
http://localhost:3000(o una porta diversa se la 3000 è occupata), mostrando l'applicazione React predefinita.
Struttura di un progetto React generato da CRA
Quando apri la cartella del tuo progetto con un editor di codice (come VS Code), vedrai una struttura simile a questa:
my-app/
├── node_modules/ # Tutte le dipendenze del progetto
├── public/ # File statici (index.html, immagini, manifest, favicon)
│ ├── index.html # Il file HTML principale della tua applicazione
│ └── ...
├── src/ # Il cuore della tua applicazione React
│ ├── App.css # Fogli di stile per il componente App
│ ├── App.js # Il componente principale della tua applicazione
│ ├── App.test.js # File di test per App.js
│ ├── index.css # Fogli di stile globali
│ ├── index.js # Il punto di ingresso della tua applicazione React
│ ├── logo.svg # Un'immagine logo
│ ├── reportWebVitals.js # Per misurare le prestazioni web
│ └── setupTests.js # Configurazione per i test
├── .gitignore # File e cartelle da ignorare da Git
├── package.json # Metadati del progetto e lista delle dipendenze
├── package-lock.json # Dettagli precisi delle dipendenze (npm)
└── README.md # Informazioni sul progetto
La cartella src/ è dove passerai la maggior parte del tuo tempo. In particolare, index.js è il punto di ingresso dell'applicazione, dove il tuo componente React principale viene "montato" nel index.html.
index.js è il file che inizializza la tua applicazione React. Contiene il codice che renderizza il tuo componente principale (App in questo caso) nel DOM del browser. Ecco come appare:
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// Se vuoi iniziare a misurare le prestazioni della tua app, passa una funzione
// per registrare i risultati (es. reportWebVitals(console.log))
// o inviarli a un endpoint di analytics.
reportWebVitals();
Come puoi vedere, ReactDOM.createRoot crea una "root" React e root.render renderizza il componente <App /> al suo interno. Il componente <App /> è importato da App.js.
I Tuoi Primi Passi con i Componenti React e JSX
Il concetto centrale in React è il componente. Tutto in React è un componente. Immagina un'interfaccia utente come un puzzle, dove ogni pezzo è un componente. Ogni componente ha una sua logica e una sua parte di UI, e insieme formano l'intera applicazione.
Cosa sono i Componenti?
I componenti sono i blocchi costruttivi fondamentali di qualsiasi applicazione React. Ti permettono di suddividere l'interfaccia utente in parti indipendenti e riutilizzabili. Questo rende il codice più facile da capire, mantenere e sviluppare in team. Ad esempio, una pagina web potrebbe essere composta da un componente Header, un componente Sidebar, un componente MainContent e diversi componenti Card all'interno del MainContent.
In React, esistono principalmente due tipi di componenti:
- Componenti a Funzione (Functional Components): Sono semplici funzioni JavaScript che accettano un oggetto
props(proprietà) come argomento e restituiscono elementi React (generalmente JSX). Con l'introduzione degli Hooks, sono diventati il modo preferito per scrivere componenti in React, anche quelli che gestiscono lo stato interno. - Componenti a Classe (Class Components): Sono classi JavaScript che estendono
React.Componente devono implementare un metodorender()che restituisce elementi React. Prima degli Hooks, erano l'unico modo per avere uno stato interno e metodi del ciclo di vita. Oggi sono meno comuni, ma potresti incontrarli in codice legacy.
Per i principianti, ci concentreremo sui componenti a funzione con gli Hooks, in quanto sono più moderni, più semplici da scrivere e più facili da capire.
JSX: JavaScript XML
JSX è una sintassi che estende JavaScript, permettendoti di scrivere markup simile all'HTML direttamente all'interno del tuo codice JavaScript. Sembra una miscela di HTML e JavaScript, e inizialmente potrebbe sembrare strano, ma è incredibilmente potente per descrivere come dovrebbe apparire la tua UI.
Perché JSX?
- Leggibilità: Permette di visualizzare la struttura dell'UI in modo più chiaro e intuitivo rispetto alla creazione di elementi DOM con JavaScript puro.
- Espressioni JavaScript: Puoi incorporare espressioni JavaScript all'interno del JSX usando le parentesi graffe
{}. Questo rende facile inserire dati dinamici, chiamare funzioni o eseguire logica condizionale direttamente nel tuo markup. - Sicurezza: React e JSX prevengono attacchi di iniezione (come XSS) eseguendo automaticamente l'escape di qualsiasi valore embeddato nel JSX prima di renderizzarlo.
- Compilazione: Il codice JSX non viene compreso direttamente dal browser. Viene "transpilato" (convertito) in chiamate a
React.createElement()da strumenti come Babel durante il processo di build.
Regole di base di JSX:
- Un solo elemento root: Ogni componente React deve restituire un singolo elemento root. Se devi restituire più elementi adiacenti, avvolgili in un elemento padre (come un
<div>) o usa unFragment(<></>o<React.Fragment>). - Attributi in camelCase: Gli attributi HTML come
classdiventanoclassNamein JSX, efordiventahtmlFor. Questo perchéclasseforsono parole chiave riservate in JavaScript. - Tag auto-chiudenti: I tag HTML che non hanno un contenuto (come
<img>,<input>,<br/>) devono essere esplicitamente chiusi con uno slash finale (es.<img src="..." />). - Espressioni JavaScript: Per inserire codice JavaScript dinamico, usa le parentesi graffe
{}. Ad esempio,{nomeVariabile}o{unaFunzione()}.
Creazione del tuo primo componente funzionale
Apri il file src/App.js nel tuo progetto il-mio-primo-progetto-react. Questo è il componente principale che viene renderizzato da index.js. Lo modificheremo per capire come funziona.
// src/App.js
import React from 'react'; // Non è strettamente necessario importare React con le versioni più recenti, ma è una buona pratica
import './App.css'; // Importiamo i fogli di stile per questo componente
// Questo è un componente a funzione
function App() {
const nome = "Mondo";
return (
<div className="App">
<header className="App-header">
<h1>Ciao, {nome}! Benvenuto nel tuo primo componente React.</h1>
<p>
Stiamo imparando a sviluppare con React.
</p>
<button => alert('Hai cliccato il bottone!')}>
Cliccami!
</button>
</header>
</div>
);
}
export default App; // Esportiamo il componente per poterlo usare altrove
Spiegazione del codice:
import React from 'react';: Anche se con le versioni più recenti di React non è sempre obbligatorio importareReactquando si usa JSX (grazie a una trasformazione automatica), è comunque una buona pratica e non fa male includerlo.import './App.css';: Stiamo importando un file CSS specifico per questo componente. Questo è un esempio di come React ti permetta di incapsulare stili insieme alla logica del componente.function App() { ... }: Questa è la definizione del nostro componente a funzione. Il nome del componente deve iniziare con una lettera maiuscola (convenzione React).const nome = "Mondo";: Qui definiamo una semplice variabile JavaScript.return (...): Il componente restituisce il markup JSX che descrive la sua UI.className="App": In JSX, usiamoclassNameinvece diclassper assegnare classi CSS.<h1>Ciao, {nome}! ...</h1>: Qui vediamo un esempio di espressione JavaScript all'interno del JSX. La variabilenomeviene inserita dinamicamente nel titolo.<button => alert('Hai cliccato il bottone!')}>: Questo è un gestore di eventi.onClickè un attributo JSX che accetta una funzione JavaScript. Quando il bottone viene cliccato, la funzionealertverrà eseguita.export default App;: Questa riga rende il componenteAppdisponibile per essere importato e utilizzato in altri file JavaScript (comeindex.js).
Salva il file App.js. Se il tuo server di sviluppo è ancora in esecuzione (npm start), vedrai automaticamente gli aggiornamenti nel browser. Congratulazioni, hai modificato il tuo primo componente React!
Gestire i Dati: Props e State in React
Un'applicazione web non è statica; deve interagire con i dati. In React, ci sono due modi principali per gestire i dati all'interno dei componenti: le Props e lo State. Comprendere la differenza tra questi due è fondamentale per costruire applicazioni React efficaci.
Props (Properties): Dati in entrata
Le Props sono un meccanismo per passare dati da un componente padre a un componente figlio. Pensa alle props come agli argomenti di una funzione. Un componente padre "passa" delle proprietà (props) ai suoi componenti figli, e i figli "ricevono" queste proprietà per visualizzare informazioni o per comportarsi in un certo modo.
Caratteristiche delle Props:
- Unidirezionali: I dati fluiscono in una sola direzione: dal componente padre al figlio. Un componente figlio non può modificare direttamente le props che ha ricevuto dal padre. Sono "read-only".
- Immutabili: Una volta che un componente riceve delle props, non può cambiarle. Se il padre vuole che le props cambino, deve passare nuove props al figlio.
- Riutilizzabilità: Le props rendono i componenti altamente riutilizzabili. Puoi creare un componente generico (es. un bottone) e poi personalizzarlo passandogli props diverse (es. testo del bottone, colore, funzione
onClick).
Come passare e ricevere Props:
Creiamo un nuovo componente Saluto in src/Saluto.js.
// src/Saluto.js
import React from 'react';
function Saluto(props) { // Il componente riceve un oggetto 'props' come argomento
return (
<h2>Ciao, {props.nome}!</h2>
);
}
export default Saluto;
Ora, usiamo questo componente Saluto all'interno di App.js e passiamogli una prop nome:
// src/App.js (modificato)
import React from 'react';
import './App.css';
import Saluto from './Saluto'; // Importiamo il nostro nuovo componente Saluto
function App() {
const utente = "Alice";
return (
<div className="App">
<header className="App-header">
<h1>Benvenuto nella mia App React!</h1>
{/* Passiamo la prop 'nome' al componente Saluto */}
<Saluto nome={utente} />
<Saluto nome="Bob" /> {/* Possiamo riutilizzare il componente con props diverse */}
<Saluto nome="Charlie" />
<p>
Questi sono saluti dinamici grazie alle props.
</p>
</header>
</div>
);
}
export default App;
Salva entrambi i file. Vedrai ora tre saluti diversi renderizzati, ognuno con un nome passato come prop. È chiaro come il componente Saluto sia generico e il suo contenuto sia determinato dalle props che riceve.
State (Stato): Dati interni mutabili
Lo State è un oggetto JavaScript che contiene dati specifici per un componente e che possono cambiare nel tempo. Quando lo stato di un componente cambia, React "re-renderizza" quel componente e i suoi figli, aggiornando l'interfaccia utente per riflettere i nuovi dati.
Caratteristiche dello State:
- Interno al componente: Lo stato è gestito all'interno del componente in cui è definito. Non è direttamente accessibile da altri componenti (a meno che non venga passato tramite props).
- Mutabile (ma con regole): Lo stato può e deve essere modificato. Tuttavia, React ha un modo specifico per farlo: devi usare una funzione speciale fornita da React (con gli Hooks, è
useState). Non modificare mai lo stato direttamente! Questo è un errore comune che può portare a comportamenti inaspettati. - Trigger di re-render: Un cambiamento nello stato di un componente fa sì che React esegua nuovamente la funzione del componente (o il metodo
renderper i componenti a classe) e aggiorni il DOM virtuale, e di conseguenza il DOM reale se ci sono differenze.
L'Hook useState
Per gestire lo stato nei componenti a funzione, React ci fornisce gli Hooks. Il più fondamentale tra questi è useState.
useState è una funzione che accetta un argomento: il valore iniziale dello stato. Restituisce un array contenente due elementi:
- Il valore corrente dello stato.
- Una funzione per aggiornare lo stato.
Vediamo un esempio classico: un contatore.
// src/Contatore.js (nuovo file)
import React, { useState } from 'react'; // Importiamo l'Hook useState
function Contatore() {
// Dichiarazione di una variabile di stato 'conteggio'
// 'conteggio' è il valore attuale, 'setConteggio' è la funzione per aggiornarlo
// Il valore iniziale è 0
const [conteggio, setConteggio] = useState(0);
const incrementa = () => {
setConteggio(conteggio + 1); // Usiamo setConteggio per aggiornare lo stato
};
const decrementa = () => {
setConteggio(conteggio - 1); // Anche qui, usiamo la funzione di aggiornamento
};
return (
<div>
<h3>Contatore: {conteggio}</h3>
<button
<button
</div>
);
}
export default Contatore;
Ora, integra Contatore in App.js:
// src/App.js (modificato)
import React from 'react';
import './App.css';
import Saluto from './Saluto';
import Contatore from './Contatore'; // Importiamo il Contatore
function App() {
return (
<div className="App">
<header className="App-header">
<h1>Benvenuto nella mia App React!</h1>
<Saluto nome="Alice" />
<Saluto nome="Bob" />
<hr/> {/* Linea orizzontale per separare gli esempi */}
<Contatore /> {/* Inseriamo il nostro contatore */}
</header>
</div>
);
}
export default App;
Salva e prova il contatore. Noterai che cliccando i bottoni, il numero cambia e l'interfaccia si aggiorna automaticamente. Questo è il potere dello stato in React!
Differenze chiave tra Props e State:
| Caratteristica | Props | State |
|---|---|---|
| Gestione | Passate dal componente padre al figlio | Gestito internamente dal componente |
| Mutabilità | Immutabili (read-only) | Mutabile (modificabile con useState) |
| Scopo | Configurare il componente o passargli dati | Gestire dati che cambiano nel tempo |
| Flusso | Unidirezionale (padre -> figlio) | Interno al componente (ma può influire sui figli tramite props) |
Interazione Utente e Gestione degli Eventi
Le applicazioni web moderne sono interattive. Gli utenti cliccano bottoni, digitano in campi di testo, muovono il mouse. React fornisce un sistema robusto per gestire questi eventi utente in modo dichiarativo, simile a come si farebbe con l'HTML tradizionale, ma con alcune importanti differenze.
Come funzionano gli eventi in React
React usa un sistema di eventi sintetici. Questo significa che React avvolge gli eventi nativi del browser in un proprio oggetto SyntheticEvent che garantisce la compatibilità cross-browser. Non devi preoccuparti delle differenze tra i browser per la gestione degli eventi; React lo fa per te.
Sintassi per la gestione degli eventi:
In JSX, i gestori di eventi sono specificati come attributi con la convenzione camelCase. Ad esempio, onclick in HTML diventa onClick in React, onchange diventa onChange, e così via.
Il valore dell'attributo dell'evento deve essere una funzione JavaScript, non una stringa.
// Esempio di gestore di eventi
<button
Dove handleClick è una funzione definita all'interno del tuo componente.
Esempio: un bottone che cambia un testo
Riprendiamo il nostro componente App.js e aggiungiamo un testo che cambia quando clicchiamo un bottone.
// src/App.js (modificato)
import React, { useState } from 'react'; // Importiamo useState
import './App.css';
function App() {
const [messaggio, setMessaggio] = useState('Clicca il bottone per cambiare il messaggio!');
// Funzione che verrà chiamata quando il bottone viene cliccato
const gestisciClick = () => {
setMessaggio('Il messaggio è stato cambiato!');
};
// Funzione che riceve l'oggetto evento (ad esempio, per un input)
const gestisciInput = (event) => {
setMessaggio(`Hai digitato: ${event.target.value}`);
};
return (
<div className="App">
<header className="App-header">
<h1>Gestione degli Eventi in React</h1>
<p>{messaggio}</p>
<button
Cambia Messaggio
</button>
<br/><br/>
<input
type="text"
placeholder="Digita qualcosa..."
style={{ padding: '10px', fontSize: '1em' }}
/>
</header>
</div>
);
}
export default App;
Spiegazione:
const [messaggio, setMessaggio] = useState(...): Dichiaramo una variabile di stato per il messaggio visualizzato.const gestisciClick = () => { ... }: Questa è la funzione che verrà eseguita quando l'eventoonClickdel bottone si verifica. All'interno, aggiorniamo lo statomessaggio.<button>: Qui, passiamo la funzionegestisciClickcome handler per l'eventoonClick. Nota bene: non chiamiamo la funzione (gestisciClick()), ma passiamo un riferimento ad essa. React la chiamerà per noi quando l'evento si verifica.const gestisciInput = (event) => { ... }: Questa funzione riceve l'oggettoeventcome parametro. L'oggettoeventcontiene informazioni sull'evento, inclusievent.targetche si riferisce all'elemento DOM che ha scatenato l'evento (in questo caso, l'input).event.target.valueci dà il valore corrente dell'input.<input />: Per gli input, l'eventoonChangesi scatena ad ogni modifica del valore dell'input. Questo ci permette di catturare ciò che l'utente digita in tempo reale.
Salva il file e prova l'applicazione. Vedrai che il messaggio cambia sia cliccando il bottone che digitando nel campo di input. La gestione degli eventi è un pilastro dell'interattività in React.
Il Ciclo di Vita dei Componenti e l'Hook useEffect
Ogni componente React attraversa una serie di fasi dalla sua creazione alla sua distruzione. Questo è chiamato il ciclo di vita del componente. Comprendere il ciclo di vita è cruciale per eseguire operazioni specifiche in momenti precisi, come fetching dati da un'API, impostare listener di eventi globali, o pulire risorse quando un componente non è più necessario.
Nei componenti a funzione, l'Hook useEffect è il principale strumento per gestire gli "effetti collaterali" (side effects) che avvengono durante il ciclo di vita del componente. Gli effetti collaterali sono tutte quelle operazioni che interagiscono con il mondo esterno all'applicazione React, come:
- Chiamate API per fetching dati.
- Manipolazione diretta del DOM.
- Impostazione di timer o intervalli (
setTimeout,setInterval). - Iscrizione a eventi globali o librerie esterne.
L'Hook useEffect in dettaglio
useEffect accetta due argomenti:
- Una funzione che contiene la logica dell'effetto collaterale.
- Un array di dipendenze (opzionale).
useEffect(() => {
// La tua logica dell'effetto collaterale
// Questa funzione viene eseguita dopo ogni render del componente per impostazione predefinita
return () => {
// Funzione di cleanup (opzionale)
// Questa viene eseguita prima che l'effetto venga eseguito di nuovo o quando il componente viene smontato
};
}, [dipendenza1, dipendenza2]); // Array di dipendenze (opzionale)
Vediamo i diversi scenari basati sull'array di dipendenze:
-
Nessun array di dipendenze:
useEffect(() => { /* ... */ });- L'effetto viene eseguito dopo ogni render del componente. Usalo con cautela, poiché può portare a loop infiniti se non gestito correttamente (es. aggiornare lo stato all'interno dell'effetto senza condizioni).
-
Array di dipendenze vuoto:
useEffect(() => { /* ... */ }, []);- L'effetto viene eseguito solo una volta dopo il primo render (montaggio del componente). È l'equivalente del metodo
componentDidMountnei componenti a classe. Ideale per fetching dati iniziali o per impostare listener globali.
- L'effetto viene eseguito solo una volta dopo il primo render (montaggio del componente). È l'equivalente del metodo
-
Array di dipendenze con valori:
useEffect(() => { /* ... */ }, [prop1, state2]);- L'effetto viene eseguito dopo il primo render e ogni volta che una delle dipendenze nell'array cambia. Questo è l'equivalente di
componentDidMount+componentDidUpdate(per quelle dipendenze specifiche). React confronta i valori delle dipendenze tra un render e l'altro. Se un valore è diverso, l'effetto viene rieseguito.
- L'effetto viene eseguito dopo il primo render e ogni volta che una delle dipendenze nell'array cambia. Questo è l'equivalente di
La Funzione di Cleanup
Spesso, quando un effetto imposta qualcosa (come un timer, un listener, o una sottoscrizione), è necessario "pulire" quella risorsa quando il componente non è più necessario o quando l'effetto deve essere rieseguito con nuove dipendenze. Puoi farlo restituendo una funzione dalla funzione dell'effetto.
Questa funzione di cleanup viene eseguita:
- Prima che l'effetto venga rieseguito (se le dipendenze cambiano).
- Quando il componente viene smontato dal DOM (equivalente a
componentWillUnmount).
Esempio di useEffect con fetching dati (simulato):
Creiamo un componente FetchDati che simula il recupero di dati da un'API.
// src/FetchDati.js (nuovo file)
import React, { useState, useEffect } from 'react';
function FetchDati() {
const [dati, setDati] = useState(null);
const [caricamento, setCaricamento] = useState(true);
const [errore, setErrore] = useState(null);
// L'effetto verrà eseguito solo una volta al montaggio del componente (grazie all'array vuoto [])
useEffect(() => {
console.log('Fetching dati...');
// Simuliamo una chiamata API con un ritardo
const timer = setTimeout(() => {
fetch('https://jsonplaceholder.typicode.com/todos/1') // Esempio di API pubblica
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
setDati(data);
setCaricamento(false);
})
.catch(error => {
setErrore(error);
setCaricamento(false);
});
}, 2000); // Ritardo di 2 secondi
// Funzione di cleanup: viene eseguita se il componente viene smontato
// o se l'effetto dovesse rieseguire (non in questo caso con [])
return () => {
console.log('Cleanup: clearing timeout');
clearTimeout(timer);
};
}, []); // Array di dipendenze vuoto: esegui solo una volta al montaggio
if (caricamento) {
return <p>Caricamento dati...</p>;
}
if (errore) {
return <p>Errore durante il caricamento: {errore.message}</p>;
}
return (
<div>
<h3>Dati Caricati:</h3>
<p>Titolo: {dati.title}</p>
<p>Completato: {dati.completed ? 'Sì' : 'No'}</p>
</div>
);
}
export default FetchDati;
Integra FetchDati in App.js:
// src/App.js (modificato)
import React from 'react';
import './App.css';
import FetchDati from './FetchDati'; // Importiamo il componente FetchDati
function App() {
return (
<div className="App">
<header className="App-header">
<h1>Il tuo Componente con Fetching Dati</h1>
<FetchDati />
</header>
</div>
);
}
export default App;
Salva e osserva. Dopo circa due secondi, i dati verranno caricati e visualizzati. Se rimuovi il componente FetchDati da App.js mentre è in fase di caricamento (simulando uno smontaggio), vedrai il messaggio di cleanup nella console.
useEffect è uno degli Hooks più potenti e versatili, ma richiede pratica per essere padroneggiato. È fondamentale capire l'importanza dell'array di dipendenze per evitare problemi di performance o bug legati a effetti non desiderati.
Esempi Pratici: Costruire una Lista di Cose da Fare (Todo List)
Ora che abbiamo coperto i concetti fondamentali – componenti, JSX, props, state, eventi e useEffect – è il momento di mettere tutto insieme per costruire una piccola ma completa applicazione: una Lista di Cose da Fare (Todo List). Questo è un progetto classico per i principianti e ti aiuterà a consolidare le tue conoscenze.
Requisiti della nostra Todo List
La nostra Todo List avrà le seguenti funzionalità:
- Visualizzare una lista di attività (todos).
- Aggiungere nuove attività.
- Segnare un'attività come completata/non completata.
- Eliminare un'attività.
Struttura dei Componenti
Suddivideremo l'applicazione in tre componenti principali:
App.js: Il componente padre che gestirà lo stato globale dell'intera lista di attività e le funzioni per modificarla.TodoForm.js: Un componente per l'input e il bottone di aggiunta di nuove attività.TodoList.js: Un componente che visualizzerà la lista di attività e passerà le singole attività al componenteTodoItem.TodoItem.js: Un singolo componente per ogni attività, che mostrerà il testo, un bottone per completare e un bottone per eliminare.
Implementazione Passo-Passo
1. App.js: Il componente principale e gestore dello stato
Iniziamo con App.js. Qui terremo lo stato di tutte le attività. Useremo useState per gestire l'array todos.
// src/App.js
import React, { useState } from 'react';
import './App.css'; // Puoi rimuovere o adattare il CSS predefinito di CRA
import TodoForm from './TodoForm';
import TodoList from './TodoList';
function App() {
const [todos, setTodos] = useState([]); // Array di oggetti todo
// Funzione per aggiungere un nuovo todo
const addTodo = (text) => {
const newTodo = {
id: Date.now(), // ID unico basato sul timestamp
text: text,
completed: false,
};
setTodos([...todos, newTodo]); // Aggiungiamo il nuovo todo all'array esistente
};
// Funzione per segnare un todo come completato/non completato
const toggleComplete = (id) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
));
};
// Funzione per eliminare un todo
const deleteTodo = (id) => {
setTodos(todos.filter(todo => todo.id !== id));
};
return (
<div className="App">
<header className="App-header">
<h1>La Mia Todo List</h1>
<TodoForm addTodo={addTodo} /> {/* Passiamo la funzione addTodo come prop */}
<TodoList
todos={todos}
toggleComplete={toggleComplete}
deleteTodo={deleteTodo}
/> {/* Passiamo l'array di todos e le funzioni come props */}
</header>
</div>
);
}
export default App;
Spiegazione di App.js:
const [todos, setTodos] = useState([]);: Inizializziamo lo statotodoscome un array vuoto. Ognitodosarà un oggetto{ id, text, completed }.addTodo,toggleComplete,deleteTodo: Queste funzioni sono definite inAppperché è qui che risiede lo statotodos. Modificano lo stato utilizzandosetTodos.addTodo: Crea un nuovo oggettotodocon un ID unico e lo aggiunge all'arraytodosusando l'operatore spread...per creare un nuovo array (ricorda, non modificare lo stato direttamente).toggleComplete: Mappa l'arraytodose, se trova l'ID corrispondente, crea un nuovo oggettotodocon la proprietàcompletedinvertita. Altrimenti, restituisce iltodooriginale. Anche qui, creiamo un nuovo array.deleteTodo: Filtra l'arraytodos, rimuovendo l'attività con l'ID specificato.
- Passiamo queste funzioni e l'array
todosai componenti figli come props.
2. TodoForm.js: Aggiungere nuove attività
Questo componente avrà un campo di input e un bottone per aggiungere nuove attività. Riceverà la funzione addTodo come prop dal componente App.
// src/TodoForm.js
import React, { useState } from 'react';
function TodoForm({ addTodo }) { // Destructuring per accedere direttamente a 'addTodo'
const [inputValue, setInputValue] = useState('');
const handleSubmit = (event) => {
event.preventDefault(); // Previene il ricaricamento della pagina al submit del form
if (!inputValue.trim()) return; // Non aggiungere todo vuoti
addTodo(inputValue); // Chiamiamo la funzione passata come prop
setInputValue(''); // Resettiamo l'input dopo l'aggiunta
};
return (
<form style={{ marginBottom: '20px' }}>
<input
type="text"
placeholder="Aggiungi una nuova attività..."
value={inputValue} => setInputValue(e.target.value)}
style={{ padding: '10px', fontSize: '1em', marginRight: '10px', borderRadius: '5px', border: '1px solid #ddd' }}
/>
<button
type="submit"
style={{ padding: '10px 15px', fontSize: '1em', backgroundColor: '#61dafb', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer' }}
>
Aggiungi
</button>
</form>
);
}
export default TodoForm;
3. TodoList.js: Visualizzare la lista
Questo componente riceverà l'array todos e le funzioni di callback. Renderizzerà un componente TodoItem per ogni attività nell'array.
// src/TodoList.js
import React from 'react';
import TodoItem from './TodoItem';
function TodoList({ todos, toggleComplete, deleteTodo }) {
return (
<div style={{ width: '100%', maxWidth: '500px' }}>
{todos.length === 0 ? (
<p>Nessuna attività. Aggiungine una!</p>
) : (
<ul style={{ listStyle: 'none', padding: 0 }}>
{todos.map(todo => (
<TodoItem
key={todo.id} // La prop 'key' è fondamentale per le liste in React!
todo={todo}
toggleComplete={toggleComplete}
deleteTodo={deleteTodo}
/>
))}
</ul>
)}
</div>
);
}
export default TodoList;
Spiegazione di TodoList.js:
todos.map(...): Il metodomapè usato per iterare su ogni elemento dell'arraytodose restituire un componenteTodoItemper ciascuno.key={todo.id}: Questa è una prop speciale e obbligatoria quando si renderizzano liste di elementi in React. React usa lakeyper identificare in modo univoco ogni elemento della lista e ottimizzare il processo di aggiornamento del DOM. Lakeydovrebbe essere un valore stabile e unico per ogni elemento (l'ID del todo è perfetto).
4. TodoItem.js: Il singolo elemento della lista
Questo componente riceverà un singolo oggetto todo e le funzioni toggleComplete e deleteTodo. Sarà responsabile di visualizzare il testo dell'attività, il suo stato di completamento e i bottoni per le azioni.
// src/TodoItem.js
import React from 'react';
function TodoItem({ todo, toggleComplete, deleteTodo }) {
const itemStyle = {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
padding: '10px',
marginBottom: '8px',
backgroundColor: todo.completed ? '#d4edda' : '#f8f9fa', // Colore diverso se completato
border: `1px solid ${todo.completed ? '#28a745' : '#ccc'}`, // Bordo diverso
borderRadius: '5px',
textDecoration: todo.completed ? 'line-through' : 'none',
color: todo.completed ? '#6c757d' : '#343a40'
};
const buttonStyle = {
padding: '8px 12px',
fontSize: '0.8em',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
marginLeft: '5px'
};
return (
<li style={itemStyle}>
<span => toggleComplete(todo.id)} style={{ cursor: 'pointer', flexGrow: 1 }}>
{todo.text}
</span>
<div>
<button => toggleComplete(todo.id)}
style={{ ...buttonStyle, backgroundColor: todo.completed ? '#dc3545' : '#28a745', color: 'white' }}
>
{todo.completed ? 'Annulla' : 'Completa'}
</button>
<button => deleteTodo(todo.id)}
style={{ ...buttonStyle, backgroundColor: '#ffc107', color: '#333' }}
>
Elimina
</button>
</div>
</li>
);
}
export default TodoItem;
Salva tutti i file e avvia l'applicazione (npm start). Avrai ora una Todo List completamente funzionante, costruita pezzo per pezzo con i concetti che abbiamo imparato! Questo esempio dimostra come i componenti comunicano tramite props e come lo stato gestisce i dati dinamici.
Errori Comuni per i Principianti e Come Risolverli
Iniziare con React può essere entusiasmante, ma è normale incontrare alcuni ostacoli. Conoscere gli errori più comuni ti aiuterà a identificarli e risolverli più rapidamente.
-
Dimenticare la
keynelle liste: Questo è forse l'errore più comune. Quando renderizzi una lista di elementi (ad esempio, conmap), React ti avviserà con un warning nella console:Warning: Each child in a list should have a unique "key" prop.. Lakeyaiuta React a identificare quali elementi sono cambiati, aggiunti o rimossi in modo efficiente. Usa sempre un ID unico e stabile per lakey.- Soluzione: Assicurati che ogni elemento figlio diretto di una lista (es.
<li key={item.id}>) abbia una propkeyunivoca.
- Soluzione: Assicurati che ogni elemento figlio diretto di una lista (es.
-
Modificare lo stato direttamente: Un errore frequente è tentare di modificare una variabile di stato come una normale variabile JavaScript, ad esempio
todos.push(newTodo)oconteggio = conteggio + 1;. Questo non attiverà un re-render del componente e la UI non si aggiornerà.- Soluzione: Usa sempre la funzione di aggiornamento fornita da
useState(es.setTodos([...todos, newTodo]),setConteggio(conteggio + 1)). Per gli oggetti e gli array, assicurati di creare una nuova copia.
- Soluzione: Usa sempre la funzione di aggiornamento fornita da
-
Loop infiniti con
useEffect: Se unuseEffectaggiorna lo stato senza un array di dipendenze (o con un array di dipendenze che include lo stato che viene aggiornato), può causare un loop infinito dove l'effetto aggiorna lo stato, che causa un re-render, che riesegue l'effetto, e così via.- Soluzione: Controlla attentamente l'array di dipendenze del tuo
useEffect. Se l'effetto deve essere eseguito solo una volta al montaggio, usa[]. Se dipende da alcune variabili, includile nell'array. Se non dipende da nulla e non aggiorna lo stato, potresti non aver bisogno diuseEffect.
- Soluzione: Controlla attentamente l'array di dipendenze del tuo
-
Cannot read properties of undefined(o simili): Questo errore si verifica spesso quando tenti di accedere a una proprietà di un oggetto che èundefinedonull. Questo può accadere se le props non vengono passate correttamente, se lo stato non è ancora stato inizializzato con i dati attesi (ad esempio, durante un fetching asincrono), o se c'è un errore di battitura nel nome di una prop o di una variabile di stato.- Soluzione: Controlla l'origine dei dati (props o state). Assicurati che siano definiti prima di tentare di accedervi. Durante il fetching dati, mostra uno stato di caricamento (
if (loading) return <p>Caricamento...</p>;). Usa l'optional chaining (dati?.proprieta) o il rendering condizionale.
- Soluzione: Controlla l'origine dei dati (props o state). Assicurati che siano definiti prima di tentare di accedervi. Durante il fetching dati, mostra uno stato di caricamento (
-
Non chiudere i tag JSX o non avere un singolo elemento root: JSX richiede che tutti i tag siano chiusi (es.
<img />,<br />) e che ogni componente restituisca un singolo elemento padre (o unFragment).- Soluzione: Aggiungi lo slash finale ai tag auto-chiudenti. Avvolgi più elementi adiacenti in un
<div>o in un<React.Fragment>(o la sua forma abbreviata<></>).
- Soluzione: Aggiungi lo slash finale ai tag auto-chiudenti. Avvolgi più elementi adiacenti in un
-
Confusione tra JSX e HTML/JavaScript: Ricorda che JSX ha alcune differenze rispetto all'HTML (es.
classNameinvece diclass,htmlForinvece difor) e che le espressioni JavaScript devono essere racchiuse tra parentesi graffe{}.- Soluzione: Fai attenzione alle differenze di sintassi e consulta la documentazione di React se hai dubbi.
Sviluppare con React significa imparare a leggere i messaggi di errore nella console del browser. Sono i tuoi migliori amici per il debugging!
Prossimi Passi nel Tuo Percorso React
Congratulazioni! Hai completato questa guida introduttiva a React e hai costruito la tua prima applicazione interattiva. Questo è un ottimo punto di partenza, ma il mondo di React è vasto e offre molte altre opportunità di apprendimento. Ecco alcuni prossimi passi e aree in cui potresti voler approfondire:
- Routing con React Router DOM: Le applicazioni reali hanno più pagine. React Router DOM è la libreria standard per gestire la navigazione tra diverse "pagine" (componenti) nella tua Single Page Application (SPA).
- Gestione dello Stato Avanzata: Per applicazioni più grandi, lo stato può diventare complesso. Esplora:
- Context API: Uno strumento integrato in React per passare dati attraverso l'albero dei componenti senza dover passare manualmente le props a ogni livello (prop drilling).
- Redux / Zustand / Jotai: Librerie esterne per una gestione dello stato più robusta e scalabile, ideali per applicazioni complesse con stato globale distribuito.
- Fetching Dati Reali: Abbiamo simulato una chiamata API con
fetch. Approfondisci:- Axios: Una popolare libreria HTTP client per fare richieste API in modo più semplice e potente.
- React Query / SWR: Librerie per la gestione e la cache delle richieste dati, che semplificano notevolmente il fetching, il caching, la sincronizzazione e l'aggiornamento dei dati lato client.
- Styling in React: Ci sono molti modi per stilizzare i tuoi componenti:
- CSS Modules: Incapsula gli stili CSS a livello di componente per evitare conflitti di nomi.
- Styled Components / Emotion: Librerie che ti permettono di scrivere CSS direttamente nel tuo JavaScript (CSS-in-JS).
- Tailwind CSS: Un framework CSS utility-first che ti permette di costruire design complessi direttamente nel tuo markup con classi predefinite.
- Hooks Avanzati e Custom Hooks: Esplora altri Hooks come
useReducer(per gestire stati complessi),useContext(per accedere al Context API),useCallback,useMemo(per ottimizzare le performance) e impara a creare i tuoi Custom Hooks per riutilizzare la logica di stato tra componenti. - Testing: Impara a scrivere test per i tuoi componenti React usando librerie come Jest e React Testing Library, per assicurarti che la tua applicazione funzioni come previsto e per prevenire regressioni.
- TypeScript con React: Man mano che i progetti crescono, l'aggiunta di TypeScript può migliorare la manutenibilità, la leggibilità e la robustezza del codice, fornendo type checking statico.
- Deployment: Scopri come mettere online la tua applicazione React usando servizi come Vercel, Netlify o GitHub Pages.
React è una libreria potente e in continua evoluzione. Continua a praticare, a costruire progetti e a esplorare la documentazione ufficiale. La chiave per diventare uno sviluppatore React esperto è la pratica costante e la curiosità di imparare sempre cose nuove. In bocca al lupo per il tuo percorso nel mondo di React!