Terug naar Blog

Hoe Bouw Je een Valutaconverter met React en een Realtime Wisselkoers API

V
Vlado Grigirov
April 07, 2026
"Currency API" "React" "Tutorial" "JavaScript" "Exchange Rates" "Finexly"

Hoe Bouw Je een Valutaconverter met React en een Realtime Wisselkoers API

Een valutaconverter bouwen met React is een uitstekend project voor developers die API-integratie, React-hooks en state management in praktijk willen brengen. In deze stap-voor-stap tutorial bouw je een volledig functionele valutaconverter die realtime wisselkoersen ophaalt van een valuta-API, meer dan 170 valuta's ondersteunt en fouten netjes afhandelt — allemaal met moderne React-patronen.

Als je nieuw bent en wilt begrijpen hoe wisselkoersen werken, bekijk dan onze uitleg over wisselkoersen voordat je begint.

Wat Je Gaat Bouwen

Aan het einde van dit tutorial heb je een React-valutaconverter die:

  • Realtime wisselkoersen ophaalt van de Finexly API
  • Meer dan 170 valuta's ondersteunt via een dropdownmenu
  • Bedragen realtime converteert terwijl de gebruiker typt (met debouncing)
  • Laadstatus en API-fouten netjes afhandelt
  • De koers en de tijdstempel van de laatste update weergeeft

Projectstructuur:

currency-converter/
├── src/
│   ├── components/
│   │   └── CurrencyConverter.tsx
│   ├── hooks/
│   │   └── useExchangeRate.ts
│   ├── App.tsx
│   └── main.tsx
├── package.json
└── vite.config.ts

Vereisten

Zorg ervoor dat je het volgende hebt:

  • Node.js 18+ geïnstalleerd
  • Basiskennis van React-hooks (useState, useEffect)
  • Een gratis Finexly API-sleutel (duurt ongeveer 30 seconden)

Stap 1: React-project Opzetten

We gebruiken Vite als build-tool:

npm create vite@latest currency-converter -- --template react-ts
cd currency-converter
npm install
npm run dev

Je ontwikkelserver start op http://localhost:5173.

Stap 2: De Finexly API Begrijpen

De Finexly API biedt realtime en historische wisselkoersen voor meer dan 170 valuta's via een eenvoudige REST-interface:

GET https://finexly.com/api/v1/latest?base=USD

Een typisch antwoord:

{
  "base": "USD",
  "date": "2026-04-07",
  "rates": {
    "EUR": 0.9182,
    "GBP": 0.7871,
    "JPY": 151.42
  },
  "timestamp": 1744012800
}

Voeg je sleutel toe aan de request-header:

Authorization: Bearer JOUW_API_SLEUTEL

Je kunt je aanmelden voor een gratis plan met 1.000 verzoeken per maand.

Stap 3: De Aangepaste Hook Maken

Maak het bestand 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-fout: ${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 : "Kon wisselkoersen niet ophalen");
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    if (baseCurrency) fetchRates(baseCurrency);
  }, [baseCurrency, fetchRates]);

  return { rates, loading, error, lastUpdated };
}

Stap 4: De CurrencyConverter-component Bouwen

Maak 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>Realtime Valutaconverter</h2>

      <div className="input-row">
        <label htmlFor="amount">Bedrag</label>
        <input
          id="amount"
          type="number"
          min="0"
          value={amount}
          onChange={(e) => setAmount(e.target.value)}
          placeholder="Voer bedrag in"
        />
      </div>

      <div className="currency-row">
        <div className="select-group">
          <label htmlFor="base">Van</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="Valuta's wisselen">⇄</button>

        <div className="select-group">
          <label htmlFor="target">Naar</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>Nieuwste koersen ophalen...</p>}
        {error && <p className="error-text">⚠ {error}</p>}
        {!loading && !error && convertedAmount !== null && (
          <>
            <p className="converted-value">
              {parseFloat(amount).toLocaleString()} {baseCurrency} =&nbsp;
              <strong>{parseFloat(convertedAmount).toLocaleString()} {targetCurrency}</strong>
            </p>
            {lastUpdated && <p>Koersen bijgewerkt: {lastUpdated.toLocaleTimeString()}</p>}
          </>
        )}
      </div>
    </div>
  );
}

Stap 5: Omgevingsvariabelen

Maak een .env-bestand in de projectroot:

VITE_FINEXLY_API_KEY=jouw_api_sleutel_hier

Voeg .env toe aan je .gitignore om je sleutel te beschermen.

Stap 6: De App Verbinden

Update src/App.tsx:

import CurrencyConverter from "./components/CurrencyConverter";

function App() {
  return (
    <main>
      <CurrencyConverter />
      <footer>
        <p>Wisselkoersen aangeboden door <a href="https://finexly.com">Finexly</a></p>
      </footer>
    </main>
  );
}

export default App;

Verder Gaan

Waardevolle verbeteringen zijn: een historisch koersgrafiek via de Finexly historische API, gelijktijdige meervoudige valutaconversie, favoriete valutaparen opgeslagen in localStorage, en server-side rendering met Next.js.

Veelgestelde Vragen

Wat is de beste wisselkoers API voor React? Voor React-apps heb je een REST API nodig die CORS ondersteunt. De Finexly API ondersteunt CORS op alle abonnementen en biedt meer dan 170 valuta's met een gratis laag.

Hoe vaak worden wisselkoersen bijgewerkt? De Finexly API werkt koersen elke 60 seconden bij voor realtime-abonnementen en eenmaal per dag voor standaardabonnementen.

Kan ik een valuta-API gebruiken in een client-side React-app? Ja, als de API CORS ondersteunt. Voor productie-apps is het het beste om verzoeken via je eigen backend te routeren.

Hoe voorkom ik dat mijn API-sleutel in React wordt blootgesteld? Gebruik voor development het .env-bestand van Vite met het prefix VITE_. Voor productie: routeer verzoeken via een Next.js API Route of serverless functie.

Hoe converteer ik tussen twee niet-USD-valuta's? De Finexly API ondersteunt elke basisvaluta op alle abonnementen, wat dit aanzienlijk vereenvoudigt.


Klaar om realtime wisselkoersen toe te voegen aan je React-app? Haal je gratis Finexly API-sleutel op — geen creditcard vereist. Begin met 1.000 gratis verzoeken per maand en schaal naarmate je groeit.

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 →