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 CurrencyConverterStep 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