React è una libreria JavaScript per costruire interfacce utente dichiarative e reattive.
| Aspetto | Vanilla JS | Vue | React |
|---|---|---|---|
| Approccio | Imperativo | Dichiarativo (progressivo) | Dichiarativo |
| Curva apprendimento | Media | Bassa | Media-Alta |
| Componenti | Manual nesting | SFC (.vue) | JSX |
| State management | Manual | Reactive data | useState hook |
| Performance | Dipende da dev | Buona | Ottima (Virtual DOM) |
| Community | Grande | Crescente | Molto grande |
Il metodo moderno per creare app React è utilizzare Vite.js:
Vantaggi di Vite:
my-react-app/
├── src/
│ ├── App.jsx # Componente root
│ ├── main.jsx # Entry point
│ ├── components/ # Componenti riutilizzabili
│ ├── assets/ # Immagini, font
│ └── styles/ # CSS globale
├── public/ # Asset statici
├── index.html # Template HTML
├── package.json # Dipendenze
├── vite.config.js # Config Vite
└── dist/ # Output build (generato)
Per avviare un’applicazione React, devi montare il componente radice nel DOM:
createRoot (React 18+):
ReactDOM.render()Un componente React è una funzione JavaScript che ritorna un elemento JSX.
// Componente semplice
function Welcome() {
return <h1>Ciao React!</h1>;
}
// Componente con parametri (props)
function Greeting(props) {
return <p>Benvenuto, {props.name}!</p>;
}
// Arrow function (moderna)
const Card = () => {
return (
<div className="card">
<h2>Card Title</h2>
<p>Card content</p>
</div>
);
};
// Esporta il componente
export default Card;Regole dei componenti:
Card, non card)JSX è una sintassi che permette di scrivere HTML-like code dentro JavaScript.
function App() {
const name = 'Alice';
const count = 42;
const isActive = true;
return (
<div>
{/* Variabili */}
<p>Ciao, {name}!</p>
{/* Espressioni */}
<p>Risultato: {count * 2}</p>
<p>Status: {isActive ? 'Attivo' : 'Inattivo'}</p>
{/* Funzioni */}
<p>Array: {[1, 2, 3].join(', ')}</p>
{/* Commenti */}
{/* Questo è un commento in JSX */}
</div>
);
}
export default App;function ImageComponent() {
const src = 'https://example.com/img.png';
const altText = 'Profile Picture';
return (
<div>
{/* Attributi con camelCase */}
<img src={src} alt={altText} className="profile-pic" />
<button onClick={() => console.log('Clicked!')}>Click me</button>
<input type="text" maxLength={10} disabled={false} />
{/* Attributi booleani */}
<input type="checkbox" checked={true} />
</div>
);
}Nota: class diventa className, for diventa htmlFor in JSX.
Props sono dati passati da un componente genitore a uno figlio:
// Componente figlio - riceve props
function TodoItem(props) {
return (
<div>
<h3>{props.title}</h3>
<p>{props.description}</p>
<p>Completato: {props.completed ? '✓' : '○'}</p>
</div>
);
}
// Componente genitore - passa props
function App() {
return (
<div>
<TodoItem
title="Imparare React"
description="Comprendere componenti e state"
completed={true}
/>
<TodoItem
title="Fare esercizi"
description="Pratica con componenti"
completed={false}
/>
</div>
);
}
export default App;Per renderere il codice più leggibile:
Lo state è dati che cambiano nel tempo e controllano il componente.
import { useState } from 'react';
function Counter() {
// Dichiara una variabile di stato
const [count, setCount] = useState(0);
return (
<div>
<p>Contatore: {count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
<button onClick={() => setCount(count - 1)}>-1</button>
<button onClick={() => setCount(0)}>Reset</button>
</div>
);
}
export default Counter;Sintassi useState:
state: valore attuale dello statosetState: funzione per aggiornare lo statoinitialValue: valore iniziale (numero, stringa, array, oggetto, ecc.)function UserForm() {
const [user, setUser] = useState({
name: '',
email: '',
age: 0
});
const handleChange = (e) => {
const { name, value } = e.target;
setUser(prevUser => ({
...prevUser,
[name]: value
}));
};
return (
<form>
<input
name="name"
value={user.name}
onChange={handleChange}
placeholder="Nome"
/>
<input
name="email"
value={user.email}
onChange={handleChange}
placeholder="Email"
type="email"
/>
<p>Dati: {JSON.stringify(user)}</p>
</form>
);
}function EventDemo() {
const handleClick = () => {
console.log('Button clicked!');
};
const handleSubmit = (e) => {
e.preventDefault(); // Previene submit default
console.log('Form submitted!');
};
const handleInputChange = (e) => {
console.log('Input value:', e.target.value);
};
return (
<div>
<button onClick={handleClick}>Click me</button>
<form onSubmit={handleSubmit}>
<input onChange={handleInputChange} placeholder="Type..."/>
<button type="submit">Submit</button>
</form>
</div>
);
}function LoginForm() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
console.log('Login:', { email, password });
// Invia dati a API
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
/>
<button type="submit">Login</button>
</form>
);
}function TodoList() {
const todos = [
{ id: 1, title: 'Imparare React', done: false },
{ id: 2, title: 'Fare esercizi', done: true },
{ id: 3, title: 'Progetto finale', done: false }
];
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>
<input type="checkbox" checked={todo.done} />
<span>{todo.title}</span>
</li>
))}
</ul>
);
}
export default TodoList;⚠️ Importante: sempre includi una prop key unica!
function ProductList() {
const products = [
{ id: 1, name: 'Laptop', price: 1000 },
{ id: 2, name: 'Mouse', price: 25 },
{ id: 3, name: 'Keyboard', price: 80 }
];
return (
<div>
{/* Filtrare */}
<h2>Prodotti > 50€</h2>
<ul>
{products
.filter(p => p.price > 50)
.map(p => <li key={p.id}>{p.name}: {p.price}€</li>)
}
</ul>
{/* Trasformare */}
<h2>Nomi prodotti</h2>
<ul>
{products.map(p => <li key={p.id}>{p.name.toUpperCase()}</li>)}
</ul>
</div>
);
}useEffect esegue effetti collaterali (fetch, subscribe, timer) nei componenti:
import { useState, useEffect } from 'react';
function DataFetcher() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
// Esegui effetto al mount
useEffect(() => {
fetch('https://api.example.com/data')
.then(res => res.json())
.then(json => {
setData(json);
setLoading(false);
})
.catch(err => {
setError(err.message);
setLoading(false);
});
}, []); // Dipendenza vuota = solo al mount
if (loading) return <p>Caricamento...</p>;
if (error) return <p>Errore: {error}</p>;
return <p>Dati: {JSON.stringify(data)}</p>;
}function Counter() {
const [count, setCount] = useState(0);
const [message, setMessage] = useState('');
// Esegui quando count cambia
useEffect(() => {
console.log('Count aggiornato:', count);
}, [count]); // Dipendenza: [count]
// Esegui una sola volta al mount
useEffect(() => {
console.log('Componente montato');
}, []); // Dipendenza vuota
// Esegui ad ogni render (evita se possibile)
useEffect(() => {
console.log('Componente renderizzato');
}); // Nessuna dipendenza
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
// Setup: crea un timer
const interval = setInterval(() => {
setSeconds(s => s + 1);
}, 1000);
// Cleanup: pulisci il timer quando unmount
return () => clearInterval(interval);
}, []);
return <p>Secondi: {seconds}</p>;
}// Grandchild
function TodoItem({ title, onDelete }) {
return (
<li>
{title}
<button onClick={onDelete}>Elimina</button>
</li>
);
}
// Child
function TodoList({ todos, onDeleteTodo }) {
return (
<ul>
{todos.map(todo => (
<TodoItem
key={todo.id}
title={todo.title}
onDelete={() => onDeleteTodo(todo.id)}
/>
))}
</ul>
);
}
// Parent
function App() {
const [todos, setTodos] = useState([
{ id: 1, title: 'React' },
{ id: 2, title: 'Esercizi' }
]);
const handleDelete = (id) => {
setTodos(todos.filter(t => t.id !== id));
};
return <TodoList todos={todos} onDeleteTodo={handleDelete} />;
}TODO
TODO
npm create vite@latest my-counter-app -- --template reactCounter.jsx:
count = 0Stats.jsx:
count come propApp.jsxNiccolò Maltoni