Back to Documentation
Build a Currency Converter App
Complete step-by-step tutorial to build a professional currency converter using React and the FXRateSync API
Beginner Friendly•30-45 minutes•React + TypeScript
What You'll Learn
- Setting up React with TypeScript
- Integrating FXRateSync API
- Real-time currency conversion
- Error handling best practices
- Professional UI with Tailwind CSS
- Production deployment ready
Prerequisites
- • Basic knowledge of React and TypeScript
- • Node.js 16+ installed on your machine
- • FXRateSync API key (free tier available)
- • Code editor (VS Code recommended)
Step 1: Project Setup
Let's start by creating a new React project with TypeScript and installing the necessary dependencies.
# Create a new React app with TypeScript npx create-react-app currency-converter --template typescript cd currency-converter # Install additional dependencies npm install axios tailwindcss npx tailwindcss init
Step 2: API Service Setup
Create a service to handle API calls to FXRateSync. This keeps your API logic organized and reusable.
// src/services/currencyService.ts import axios from 'axios' const API_BASE_URL = 'https://api.fxratesync.io/v1' const API_KEY = process.env.REACT_APP_FX_API_KEY export interface ConversionResult { from: string to: string amount: number converted_amount: number rate: number timestamp: string } export class CurrencyService { private static instance: CurrencyService static getInstance(): CurrencyService { if (!CurrencyService.instance) { CurrencyService.instance = new CurrencyService() } return CurrencyService.instance } async convertCurrency( from: string, to: string, amount: number ): Promise<ConversionResult> { try { const response = await axios.get( `${API_BASE_URL}/convert?from=${from}&to=${to}&amount=${amount}`, { headers: { 'X-API-Key': API_KEY } } ) return response.data } catch (error) { throw new Error('Failed to convert currency') } } async getSupportedCurrencies(): Promise<string[]> { // For this tutorial, we'll use a static list return ['USD', 'EUR', 'GBP', 'JPY', 'CAD', 'AUD', 'CHF', 'CNY'] } }
Step 3: Main Component
Now let's create the main currency converter component with a clean, professional interface.
// src/components/CurrencyConverter.tsx import React, { useState, useEffect } from 'react' import { CurrencyService, ConversionResult } from '../services/currencyService' const CurrencyConverter: React.FC = () => { const [fromCurrency, setFromCurrency] = useState('USD') const [toCurrency, setToCurrency] = useState('EUR') const [amount, setAmount] = useState(100) const [result, setResult] = useState<ConversionResult | null>(null) const [loading, setLoading] = useState(false) const [error, setError] = useState<string | null>(null) const [currencies, setCurrencies] = useState<string[]>([]) const currencyService = CurrencyService.getInstance() useEffect(() => { loadCurrencies() }, []) const loadCurrencies = async () => { try { const supportedCurrencies = await currencyService.getSupportedCurrencies() setCurrencies(supportedCurrencies) } catch (err) { setError('Failed to load currencies') } } const handleConvert = async () => { if (amount <= 0) { setError('Amount must be greater than 0') return } setLoading(true) setError(null) try { const conversionResult = await currencyService.convertCurrency( fromCurrency, toCurrency, amount ) setResult(conversionResult) } catch (err) { setError('Conversion failed. Please try again.') } finally { setLoading(false) } } const swapCurrencies = () => { setFromCurrency(toCurrency) setToCurrency(fromCurrency) setResult(null) } return ( <div className="max-w-2xl mx-auto p-6 bg-background rounded-2xl shadow-xl"> <h1 className="text-3xl font-bold text-center text-foreground mb-8"> Currency Converter </h1> <div className="space-y-6"> {/* Amount Input */} <div> <label className="block text-sm font-medium text-foreground mb-2"> Amount </label> <input type="number" value={amount} onChange={(e) => setAmount(Number(e.target.value))} className="w-full px-4 py-3 border border-border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="Enter amount" /> </div> {/* Currency Selectors */} <div className="grid grid-cols-1 md:grid-cols-3 gap-4 items-end"> <div> <label className="block text-sm font-medium text-foreground mb-2"> From </label> <select value={fromCurrency} onChange={(e) => setFromCurrency(e.target.value)} className="w-full px-4 py-3 border border-border rounded-lg focus:ring-2 focus:ring-blue-500" > {currencies.map(currency => ( <option key={currency} value={currency}>{currency}</option> ))} </select> </div> <div className="flex justify-center"> <button onClick={swapCurrencies} className="px-4 py-2 text-primary hover:bg-primary/10 rounded-lg transition-colors" > ⇄ Swap </button> </div> <div> <label className="block text-sm font-medium text-foreground mb-2"> To </label> <select value={toCurrency} onChange={(e) => setToCurrency(e.target.value)} className="w-full px-4 py-3 border border-border rounded-lg focus:ring-2 focus:ring-blue-500" > {currencies.map(currency => ( <option key={currency} value={currency}>{currency}</option> ))} </select> </div> </div> {/* Convert Button */} <button onClick={handleConvert} disabled={loading} className="w-full bg-primary hover:bg-primary/90 disabled:opacity-50 text-background font-semibold py-3 px-6 rounded-lg transition-colors" > {loading ? 'Converting...' : 'Convert Currency'} </button> {/* Results */} {result && ( <div className="bg-success/10 border border-success/30 rounded-lg p-6"> <div className="text-center"> <div className="text-3xl font-bold text-success-foreground mb-2"> {result.converted_amount.toFixed(2)} {result.to} </div> <div className="text-sm text-success"> {result.amount} {result.from} = {result.converted_amount.toFixed(2)} {result.to} </div> <div className="text-xs text-success mt-2"> Rate: {result.rate.toFixed(4)} • {new Date(result.timestamp).toLocaleString()} </div> </div> </div> )} {/* Error Display */} {error && ( <div className="bg-destructive/10 border border-destructive/30 rounded-lg p-4 text-destructive-foreground"> {error} </div> )} </div> </div> ) } export default CurrencyConverter
Step 4: Environment Configuration
Create a `.env` file in your project root to store your API key securely.
# .env REACT_APP_FX_API_KEY=your_api_key_here
Security Note: Never commit your `.env` file to version control. Add it to your `.gitignore` file to keep your API key secure.
Step 5: Testing & Deployment
Test your application locally and prepare it for deployment.
# Test locally npm start # Build for production npm run build # Deploy to Netlify, Vercel, or your preferred hosting
Next Steps
Enhance Your App
- • Add historical rate charts
- • Implement rate alerts
- • Add favorite currency pairs
- • Include currency trend indicators
Ready to Deploy?
Get your free API key and start building amazing currency applications
Get Free API Key