Se hai un'applicazione React che inizia a rallentare, o se stai costruendo la tua prima interfaccia e senti che manca qualcosa nella gestione dello stato o nella struttura dei componenti, non sei solo. Noi di Meteora Web vediamo ogni giorno progetti React che potevano essere molto più puliti, veloci e manutenibili con le scelte giuste. Questo articolo è il nostro punto di riferimento su React: parte dalle basi e arriva ai pattern avanzati che usiamo in produzione, con esempi concreti e una visione pratica. Niente teoria astratta: qui si costruisce.
React.js da zero ad avanzato: quali sono i fondamenti di JSX, componenti e state?
React è una libreria per costruire interfacce utente. Il suo cuore sono i componenti: pezzi di UI indipendenti che gestiscono il proprio stato e si combinano come mattoncini. JSX è la sintassi che permette di scrivere HTML dentro JavaScript. Ma attenzione: JSX non è HTML. Ogni tag viene trasformato in React.createElement. Ecco un esempio base:
function Saluto({ nome }) {
return <h1>Ciao, {nome}!</h1>;
}
Lo state è ciò che rende i componenti dinamici. Con useState dichiariamo una variabile reattiva. Noi consigliamo di tenere lo stato il più vicino possibile al componente che lo usa, ed evitare di duplicare informazioni derivabili. Un errore comune è mettere tutto nello stato globale: meglio partire locale e solo dopo valutare secondividerlo.
Props: il flusso dei dati unidirezionale
Le props passano da genitore a figlio. Non modificare mai le props direttamente. Se hai bisogno di comunicare verso l'alto, passa una funzione callback. Sembra banale, ma in molti progetti ereditati abbiamo trovato mutazioni di props (e bug silenziosi).
React.js da zero ad avanzato: come usare gli Hooks per logica riutilizzabile?
Gli Hooks sono funzioni che ti permettono di "agganciarti" allo stato e al ciclo di vita di React senza usare classi. I più comuni: useState, useEffect, useRef, useMemo, useCallback. Usarli bene è la differenza tra un'app che vola e una che fa rebrand a ogni click.
Sponsored Protocol
useEffect: gestire effetti collaterali
Ogni volta che il tuo componente deve sincronizzarsi con il mondo esterno (API, DOM, timer), usi useEffect. Ma attento: senza array di dipendenze, l'effetto parte a ogni render. E se dimentichi di pulire un subscription, hai memory leak. Pattern che usiamo noi:
useEffect(() => {
const controller = new AbortController();
fetch('/api/dati', { signal: controller.signal })
.then(res => res.json())
.then(setDati);
return () => controller.abort();
}, []);
useRef per riferimenti stabili
Serve per accedere al DOM o per mantenere un valore che non deve scatenare re-render. No lo usiamo spesso per salvare timer o istanze di librerie esterne.
useMemo e useCallback: ottimizzare solo quando serve
Non avvolgere tutto in useMemo. Fallo solo se il calcolo è costoso o se passi oggetti/funzioni a componenti figli che sono memo. La regola pratica: se non vedi un collo di bottiglia, non ottimizzare.
React.js da zero ad avanzato: come gestire lo stato globale tra Context, Zustand e Redux?
Quando più componenti lontani tra loro devono condividere lo stesso stato, servono strumenti di stato globale. Noi abbiamo lavorato con tutti e tre: ecco cosa abbiamo imparato.
Context API: semplice, ma attento ai re-render
Context è built-in e va bene per dati che cambiano raramente (tema, lingua, utente). Ma se passi un oggetto che cambia spesso, tutti i consumatori si re-renderizzano. Soluzione: spezza il Context in più provider piccoli o usa useMemo per il valore.
Sponsored Protocol
Zustand: leggero e performante
Zustand è la nostra scelta preferita per progetti medi. Non richiede provider, ha una sintassi pulita e supporta i selettori automatici. Esempio:
import { create } from 'zustand';
const useStore = create((set) => ({
contatore: 0,
incrementa: () => set((state) => ({ contatore: state.contatore + 1 })),
}));
function Contatore() {
const contatore = useStore((state) => state.contatore);
return <p>{contatore}</p>;
}
Redux: potente ma con overhead
Redux ha senso per applicazioni molto grandi con logica complessa (undo/redo, middleware asincroni). Con Redux Toolkit è molto migliorato, ma per molte PMI è overkill. Noi lo usiamo solo quando il team è già abituato o la complessità lo giustifica.
React.js da zero ad avanzato: quali strategie di performance adottare?
La performance in React non è magia: è ridurre i re-render inutili e ottimizzare i carichi. Ecco le leve che usiamo in produzione.
React.memo e PureComponent
Avvolgi un componente in React.memo solo se i suoi props cambiano raramente o se il calcolo del render è pesante. Altrimenti, la comparazione delle props è uno spreco.
Lazy loading e Suspense
Carica i componenti solo quando servono. Con React.lazy e Suspense puoi dividere il bundle e migliorare il tempo di caricamento iniziale. Noi lo usiamo per ogni rotta in applicazioni con routing.
const PaginaUtenti = React.lazy(() => import('./PaginaUtenti'));
function App() {
return (
<Suspense fallback={<Spinner />}>
<PaginaUtenti />
</Suspense>
);
}
Profiling con React DevTools
Non indovinare: usa il Profiler per identificare i componenti che si re-renderizzano troppo. Il nostro workflow: registra una sessione, cerca i "fiammiferi" (componenti con molti re-render) e applica memo o ristruttura il codice.
Sponsored Protocol
React Server Components: quando usarli e come cambiano l'architettura
I Server Components (RSC) sono il futuro di React. Eseguono lato server e inviano solo il HTML serializzato al client. Questo riduce il bundle JavaScript e migliora la velocità percepita. Noi li usiamo in progetti Next.js App Router per pagine che non hanno interattività immediata.
Importante: i Server Components non possono usare Hooks o eventi. Vanno bene per recuperare dati dal database senza esporre le API al client. Per componenti interattivi, crea un Client Component separato e importalo dentro un Server Component.
Come gestire il data fetching con React Query?
React Query (ora TanStack Query) è la libreria standard per la sincronizzazione tra stato del server e stato del client. Gestisce cache, refetch, deduplicazione delle richieste e molto altro. Noi lo inseriamo in ogni progetto che fa chiamate API.
import { useQuery } from '@tanstack/react-query';
function ListaArticoli() {
const { data, isLoading, error } = useQuery({
queryKey: ['articoli'],
queryFn: () => fetch('/api/articoli').then(r => r.json()),
});
if (isLoading) return <div>Caricamento...</div>;
return <ul>{data.map(a => <li key={a.id}>{a.titolo}</li>)}</ul>;
}
Usa staleTime per evitare richieste superflue: se i dati non cambiano spesso, imposta 5 minuti. Con invalidateQueries puoi forzare un aggiornamento dopo una mutazione.
Come creare Custom Hooks per riutilizzare logica?
I Custom Hooks sono il modo migliore per estrarre logica ripetitiva. Un esempio concreto: un hook per tracciare la posizione del mouse.
function useMousePosition() {
const [position, setPosition] = useState({ x: 0, y: 0 });
useEffect(() => {
const handler = (e) => setPosition({ x: e.clientX, y: e.clientY });
window.addEventListener('mousemove', handler);
return () => window.removeEventListener('mousemove', handler);
}, []);
return position;
}
Regola d'oro: un Custom Hook deve iniziare con "use" e può chiamare altri Hooks. Non creare Hooks che fanno troppe cose: tieni ogni hook focalizzato su una responsabilità.
Sponsored Protocol
Come testare i componenti React con React Testing Library?
Testing Library ti spinge a testare il comportamento dell'utente, non l'implementazione. Noi scriviamo test che simulano click, digitazione e verificano che l'output sia corretto. Ecco un esempio:
import { render, screen, fireEvent } from '@testing-library/react';
import Contatore from './Contatore';
test('incrementa il contatore', () => {
render(<Contatore />);
const button = screen.getByText('Incrementa');
fireEvent.click(button);
expect(screen.getByText('1')).toBeInTheDocument();
});
Evita di testare lo stato interno (es. expect(contatore).toBe(1)). Invece verifica cosa vede l'utente. I test diventano più resilienti ai refactoring.
Come usare TypeScript con React per un typing robusto?
TypeScript e React sono un matrimonio che consigliamo a tutti i progetti sopra una certa dimensione. I tipi ti salvano da errori a runtime e rendono il codice auto-documentato. Ecco i pattern essenziali:
Typing delle props
interface ButtonProps {
label: string;
onClick: () => void;
variant?: 'primary' | 'secondary';
}
const Button: React.FC<ButtonProps> = ({ label, onClick, variant = 'primary' }) => {
return <button onClick={onClick} className={variant}>{label}</button>;
};
Typing degli Hooks
useState può essere tipizzato esplicitamente se il tipo non è dedotto: useState<string | null>(null). useRef con riferimento al DOM: const ref = useRef<HTMLDivElement>(null).
Sponsored Protocol
Typing del Context
interface AuthContextType {
user: User | null;
login: (creds: Credentials) => Promise<void>;
}
const AuthContext = createContext<AuthContextType | undefined>(undefined);
Animazioni in React con Framer Motion
Le animazioni migliorano l'esperienza utente se usate con misura. Noi usiamo Framer Motion per la sua API dichiarativa. Esempio di fade-in:
import { motion } from 'framer-motion';
function Card({ children }) {
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
>
{children}
</motion.div>
);
}
Ricorda: le animazioni devono servire al contenuto, non sovraccaricare. E se hai molti elementi, usa layout per animare il riposizionamento.
In sintesi: tre azioni concrete per padroneggiare React
- Rivedi i tuoi componenti: cerca re-render inutili con React DevTools Profiler. Applica
memosolo dove serve. - Scegli lo strumento giusto per lo stato globale: Context per dati statici, Zustand per progetti medi, Redux solo per complessità elevata.
- Adotta TypeScript se non lo fai già: il costo iniziale si ripaga in bug evitati e manutenibilità.
React è un ecosistema in continua evoluzione, ma i principi di componenti ben separati, stato gestito con intelligenza e performance misurata restano solidi. Noi di Meteora Web usiamo questi pattern ogni giorno nei progetti dei nostri clienti. Se hai domande o vuoi un confronto su una tua applicazione, siamo a disposizione.