ReactとリアルタイムAPIで通貨コンバーターを構築する方法
ReactでAPI統合、React Hooksを練習したい開発者にとって、通貨コンバーターの構築は最適なプロジェクトです。このステップバイステップチュートリアルでは、170以上の通貨をサポートし、リアルタイムで為替レートを取得する完全に機能する通貨コンバーターを構築します。すべてモダンなReactパターンを使用して実装します。
為替レートの仕組みについて初めて学ぶ方は、為替レートの解説をご参照ください。
構築するもの
このチュートリアルが終わると、以下の機能を持つReact通貨コンバーターが完成します:
- Finexly APIからリアルタイムの為替レートを取得
- ドロップダウンで170以上の通貨をサポート
- ユーザーが入力するたびにリアルタイムで変換(デバウンス付き)
- ローディング状態とAPIエラーを優雅に処理
- レートと最終更新タイムスタンプを表示
プロジェクト構成:
currency-converter/
├── src/
│ ├── components/
│ │ └── CurrencyConverter.tsx
│ ├── hooks/
│ │ └── useExchangeRate.ts
│ ├── App.tsx
│ └── main.tsx
├── package.json
└── vite.config.ts前提条件
開始前に以下を確認してください:
- Node.js 18+がインストール済み
- React Hooks(
useState、useEffect)の基本的な知識 - 無料のFinexly APIキー(取得に約30秒)
ステップ1:Reactプロジェクトのセットアップ
Viteをビルドツールとして使用します:
npm create vite@latest currency-converter -- --template react-ts
cd currency-converter
npm install
npm run dev開発サーバーがhttp://localhost:5173で起動します。
ステップ2:Finexly APIを理解する
Finexly APIは、シンプルなREST インターフェースを通じて170以上の通貨のリアルタイムおよび過去の為替レートを提供します:
GET https://finexly.com/api/v1/latest?base=USD典型的なレスポンス:
{
"base": "USD",
"date": "2026-04-07",
"rates": {
"EUR": 0.9182,
"GBP": 0.7871,
"JPY": 151.42
},
"timestamp": 1744012800
}リクエストヘッダーにキーを含めます:
Authorization: Bearer あなたのAPIキー無料プランに登録すると、月1,000リクエストが含まれます。
ステップ3:カスタムHookの作成
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(`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 : "為替レートの取得に失敗しました");
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
if (baseCurrency) fetchRates(baseCurrency);
}, [baseCurrency, fetchRates]);
return { rates, loading, error, lastUpdated };
}ステップ4:CurrencyConverterコンポーネントの構築
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>リアルタイム通貨コンバーター</h2>
<div className="input-row">
<label htmlFor="amount">金額</label>
<input
id="amount"
type="number"
min="0"
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="金額を入力"
/>
</div>
<div className="currency-row">
<div className="select-group">
<label htmlFor="base">変換元</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="通貨を入れ替え">⇄</button>
<div className="select-group">
<label htmlFor="target">変換先</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>最新レートを取得中...</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>レート更新: {lastUpdated.toLocaleTimeString()}</p>}
</>
)}
</div>
</div>
);
}ステップ5:環境変数
プロジェクトルートに.envファイルを作成します:
VITE_FINEXLY_API_KEY=あなたのAPIキーAPIキーを保護するために.envを.gitignoreに追加してください。
ステップ6:アプリを接続する
src/App.tsxを更新します:
import CurrencyConverter from "./components/CurrencyConverter";
function App() {
return (
<main>
<CurrencyConverter />
<footer>
<p>為替レート提供: <a href="https://finexly.com">Finexly</a></p>
</footer>
</main>
);
}
export default App;さらに進むために
基本的なコンバーターが動作したら、高価値な機能拡張として、Finexly過去データAPIを使った30日間レートチャート、同時多通貨変換、localStorageへの通貨ペア保存、Next.jsによるサーバーサイドレンダリングなどが挙げられます。
よくある質問
ReactにはどのAPIが最適ですか? CORS対応のREST APIが必要です。Finexly APIはすべてのプランでCORSをサポートし、無料枠で170以上の通貨をカバーしています。
為替レートはどのくらいの頻度で更新されますか? Finexly APIはリアルタイムプランでは60秒ごと、スタンダードプランでは1日1回更新されます。
クライアントサイドのReactアプリで通貨APIを使えますか? APIがCORSをサポートしていれば使えます。本番アプリでは、自分のバックエンドを経由してAPIリクエストを行うことをお勧めします。
ReactでAPIキーを露出させないようにするには?
開発時はViteの.envファイルでVITE_プレフィックスを使用します。本番では、Next.js API RouteやServerless関数を通じてリクエストをルーティングしてください。
USD以外の2通貨間で変換するには? Finexly APIはすべてのプランで任意のベース通貨をサポートしているため、これが大幅に簡単になります。
ReactアプリにリアルタイムAPIを追加する準備ができましたか?無料のFinexly APIキーを取得 — クレジットカード不要。月1,000回の無料リクエストから始め、成長に合わせてアップグレードしてください。
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 →