Come Creare un Convertitore di Valuta con React e un'API di Tassi di Cambio in Tempo Reale
Creare un convertitore di valuta con React è un ottimo progetto per i developer che vogliono esercitarsi con l'integrazione delle API, gli hook di React e la gestione dello stato in applicazioni reali. In questo tutorial passo dopo passo, costruirai un convertitore di valuta completamente funzionale che recupera tassi di cambio in tempo reale da un'API valutaria, supporta oltre 170 valute e gestisce gli errori in modo elegante — il tutto usando pattern React moderni.
Se sei alle prime armi e vuoi capire come funzionano i tassi di cambio, consulta il nostro articolo esplicativo sui tassi di cambio prima di iniziare.
Cosa Costruirai
Al termine di questo tutorial, avrai un convertitore di valuta React che:
- Recupera tassi di cambio in tempo reale dall'API Finexly
- Supporta oltre 170 valute tramite un menu a tendina
- Converte gli importi in tempo reale mentre l'utente digita (con debouncing)
- Gestisce gli stati di caricamento e gli errori API in modo elegante
- Mostra il tasso e il timestamp dell'ultimo aggiornamento
Struttura del progetto:
currency-converter/
├── src/
│ ├── components/
│ │ └── CurrencyConverter.tsx
│ ├── hooks/
│ │ └── useExchangeRate.ts
│ ├── App.tsx
│ └── main.tsx
├── package.json
└── vite.config.tsPrerequisiti
Prima di iniziare, assicurati di avere:
- Node.js 18+ installato
- Familiarità di base con gli hook React (
useState,useEffect) - Una chiave API Finexly gratuita (ci vogliono circa 30 secondi per ottenerla)
Passo 1: Configurare il Progetto React
Utilizzeremo Vite come strumento di build:
npm create vite@latest currency-converter -- --template react-ts
cd currency-converter
npm install
npm run devIl server di sviluppo si avvierà su http://localhost:5173.
Passo 2: Capire l'API Finexly
L'API Finexly fornisce tassi di cambio in tempo reale e storici per oltre 170 valute tramite una semplice interfaccia REST:
GET https://finexly.com/api/v1/latest?base=USDUna risposta tipica:
{
"base": "USD",
"date": "2026-04-07",
"rates": {
"EUR": 0.9182,
"GBP": 0.7871,
"JPY": 151.42
},
"timestamp": 1744012800
}Includi la tua chiave nell'intestazione della richiesta:
Authorization: Bearer LA_TUA_CHIAVE_APIPuoi registrarti per un piano gratuito con 1.000 richieste al mese.
Passo 3: Creare il Custom Hook
Crea il file src/hooks/useExchangeRate.ts:
import { useState, useEffect, useCallback } from "react";
interface ExchangeRateResult {
rates: Record<string, number> | null;
loading: boolean;
error: string | null;
lastUpdated: Date | null;
}
const API_KEY = import.meta.env.VITE_FINEXLY_API_KEY;
const BASE_URL = "https://finexly.com/api/v1";
const rateCache: Record<string, { rates: Record<string, number>; timestamp: number }> = {};
const CACHE_TTL_MS = 5 * 60 * 1000;
export function useExchangeRate(baseCurrency: string): ExchangeRateResult {
const [rates, setRates] = useState<Record<string, number> | null>(null);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null);
const [lastUpdated, setLastUpdated] = useState<Date | null>(null);
const fetchRates = useCallback(async (base: string) => {
const cached = rateCache[base];
if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) {
setRates(cached.rates);
setLastUpdated(new Date(cached.timestamp));
return;
}
setLoading(true);
setError(null);
try {
const res = await fetch(`${BASE_URL}/latest?base=${base}`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
if (!res.ok) throw new Error(`Errore API: ${res.status} ${res.statusText}`);
const data = await res.json();
rateCache[base] = { rates: data.rates, timestamp: Date.now() };
setRates(data.rates);
setLastUpdated(new Date());
} catch (err) {
setError(err instanceof Error ? err.message : "Impossibile recuperare i tassi di cambio");
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
if (baseCurrency) fetchRates(baseCurrency);
}, [baseCurrency, fetchRates]);
return { rates, loading, error, lastUpdated };
}Passo 4: Costruire il Componente CurrencyConverter
Crea src/components/CurrencyConverter.tsx:
import { useState, useMemo } from "react";
import { useExchangeRate } from "../hooks/useExchangeRate";
const CURRENCIES = [
"USD", "EUR", "GBP", "JPY", "CAD", "AUD", "CHF", "CNY",
"INR", "MXN", "BRL", "KRW", "SGD", "HKD", "NOK", "SEK",
];
export default function CurrencyConverter() {
const [amount, setAmount] = useState<string>("100");
const [baseCurrency, setBaseCurrency] = useState<string>("USD");
const [targetCurrency, setTargetCurrency] = useState<string>("EUR");
const { rates, loading, error, lastUpdated } = useExchangeRate(baseCurrency);
const convertedAmount = useMemo(() => {
if (!rates || !amount) return null;
const numAmount = parseFloat(amount);
if (isNaN(numAmount) || numAmount < 0) return null;
const rate = rates[targetCurrency];
return rate ? (numAmount * rate).toFixed(2) : null;
}, [rates, amount, targetCurrency]);
const handleSwap = () => {
setBaseCurrency(targetCurrency);
setTargetCurrency(baseCurrency);
};
return (
<div className="converter-card">
<h2>Convertitore di Valuta in Tempo Reale</h2>
<div className="input-row">
<label htmlFor="amount">Importo</label>
<input
id="amount"
type="number"
min="0"
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="Inserisci importo"
/>
</div>
<div className="currency-row">
<div className="select-group">
<label htmlFor="base">Da</label>
<select id="base" value={baseCurrency} onChange={(e) => setBaseCurrency(e.target.value)}>
{CURRENCIES.map((c) => <option key={c} value={c}>{c}</option>)}
</select>
</div>
<button className="swap-btn" onClick={handleSwap} aria-label="Scambia valute">⇄</button>
<div className="select-group">
<label htmlFor="target">A</label>
<select id="target" value={targetCurrency} onChange={(e) => setTargetCurrency(e.target.value)}>
{CURRENCIES.map((c) => <option key={c} value={c}>{c}</option>)}
</select>
</div>
</div>
<div className="result-area">
{loading && <p>Recupero tassi più recenti...</p>}
{error && <p className="error-text">⚠ {error}</p>}
{!loading && !error && convertedAmount !== null && (
<>
<p className="converted-value">
{parseFloat(amount).toLocaleString()} {baseCurrency} =
<strong>{parseFloat(convertedAmount).toLocaleString()} {targetCurrency}</strong>
</p>
{lastUpdated && <p>Tassi aggiornati: {lastUpdated.toLocaleTimeString()}</p>}
</>
)}
</div>
</div>
);
}Passo 5: Variabili d'Ambiente
Crea un file .env nella root del progetto:
VITE_FINEXLY_API_KEY=la_tua_chiave_api_quiAggiungi .env al .gitignore per proteggere la tua chiave.
Passo 6: Collegare l'App
Aggiorna src/App.tsx:
import CurrencyConverter from "./components/CurrencyConverter";
function App() {
return (
<main>
<CurrencyConverter />
<footer>
<p>Tassi di cambio forniti da <a href="https://finexly.com">Finexly</a></p>
</footer>
</main>
);
}
export default App;Per Andare Oltre
Miglioramenti di alto valore includono: un grafico dei tassi storici tramite l'API storica Finexly, conversione multivaluta simultanea, coppie di valute preferite salvate in localStorage, e rendering lato server con Next.js.
Domande Frequenti
Qual è la migliore API di tassi di cambio per React? Per le app React, hai bisogno di una REST API che supporti CORS. L'API Finexly supporta CORS su tutti i piani e copre oltre 170 valute con un livello gratuito.
Con quale frequenza vengono aggiornati i tassi di cambio? L'API Finexly aggiorna i tassi ogni 60 secondi per i piani in tempo reale e una volta al giorno per i piani standard.
Posso usare un'API valutaria in un'app React lato client? Sì, se l'API supporta CORS. Per le app in produzione, è buona pratica instradare le richieste attraverso il proprio backend.
Come evito di esporre la mia chiave API in React?
Per lo sviluppo, usa il file .env di Vite con il prefisso VITE_. Per la produzione, instrada le richieste tramite un API Route di Next.js o una funzione serverless.
Come converto tra due valute non USD? L'API Finexly supporta qualsiasi valuta base su tutti i piani, il che semplifica notevolmente questo aspetto.
Pronto ad aggiungere tassi di cambio in tempo reale alla tua app React? Ottieni la tua chiave API Finexly gratuita — nessuna carta di credito richiesta. Inizia con 1.000 richieste gratuite al mese e scala man mano che cresci.
Explore More
Vlado Grigirov
Senior Currency Markets Analyst & Financial Strategist
Vlado Grigirov is a senior currency markets analyst and financial strategist with over 14 years of experience in foreign exchange markets, cross-border finance, and currency risk management. He has wo...
View full profile →