Volver al blog

Cómo Construir un Conversor de Divisas con React y una API de Tipos de Cambio en Tiempo Real

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

Cómo Construir un Conversor de Divisas con React y una API de Tipos de Cambio en Tiempo Real

Construir un conversor de divisas con React es un excelente proyecto para los desarrolladores que quieren practicar la integración de APIs, los hooks de React y la gestión de estado en aplicaciones reales. En este tutorial paso a paso, crearás un conversor de divisas completamente funcional que obtiene tipos de cambio en tiempo real desde una API de divisas, soporta más de 170 monedas y gestiona errores de forma elegante — todo usando patrones modernos de React.

Ya sea que estés añadiendo soporte multidivisa a una aplicación existente o construyendo una herramienta de conversión independiente, esta guía cubre todo lo que necesitas. Si eres nuevo y quieres entender cómo funcionan los tipos de cambio, consulta nuestro explicador de tipos de cambio antes de comenzar.

Lo Que Construirás

Al final de este tutorial, tendrás un conversor de divisas en React que:

  • Obtiene tipos de cambio en tiempo real desde la API de Finexly
  • Soporta más de 170 divisas mediante un menú desplegable
  • Convierte cantidades en tiempo real mientras el usuario escribe (con debouncing)
  • Gestiona estados de carga y errores de API de forma elegante
  • Muestra el tipo de cambio y la marca de tiempo de la última actualización

Esta es la estructura final del componente:

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

Requisitos Previos

Antes de comenzar, asegúrate de tener:

  • Node.js 18+ instalado
  • Familiaridad básica con los hooks de React (useState, useEffect)
  • Una clave API gratuita de Finexly (tarda unos 30 segundos en obtenerla)

No necesitas conocer TypeScript — pero los ejemplos lo usan porque la seguridad de tipos hace que la integración de APIs sea mucho más limpia. Puedes eliminar los tipos si prefieres JavaScript puro.

Paso 1: Configura Tu Proyecto React

Usaremos Vite como herramienta de construcción porque es rápido, moderno y el estándar actual para el desarrollo con React.

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

Tu servidor de desarrollo se iniciará en http://localhost:5173.

Paso 2: Comprende la API de Finexly

La API de Finexly proporciona tipos de cambio en tiempo real e históricos para más de 170 divisas mediante una interfaz REST simple. Este es el endpoint que usaremos:

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

Una respuesta típica tiene este aspecto:

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

Incluye tu clave en el encabezado de la solicitud:

Authorization: Bearer TU_CLAVE_API

Puedes registrarte para un plan gratuito que incluye 1.000 solicitudes mensuales.

Paso 3: Crea el Hook Personalizado

Crea el archivo 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(`Error de 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 : "Error al obtener los tipos de cambio");
    } finally {
      setLoading(false);
    }
  }, []);

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

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

Paso 4: Construye el 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>Conversor de Divisas en Tiempo Real</h2>

      <div className="input-row">
        <label htmlFor="amount">Cantidad</label>
        <input
          id="amount"
          type="number"
          min="0"
          value={amount}
          onChange={(e) => setAmount(e.target.value)}
          placeholder="Ingresa la cantidad"
        />
      </div>

      <div className="currency-row">
        <div className="select-group">
          <label htmlFor="base">De</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="Intercambiar divisas">⇄</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>Obteniendo tipos de cambio más recientes...</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>Tipos actualizados: {lastUpdated.toLocaleTimeString()}</p>}
          </>
        )}
      </div>
    </div>
  );
}

Paso 5: Variables de Entorno

Crea un archivo .env en la raíz del proyecto:

VITE_FINEXLY_API_KEY=tu_clave_api_aqui

Añade .env a tu .gitignore para proteger tu clave API.

Paso 6: Conecta la Aplicación

Actualiza src/App.tsx:

import CurrencyConverter from "./components/CurrencyConverter";
import "./App.css";

function App() {
  return (
    <main>
      <CurrencyConverter />
      <footer>
        <p>Tipos de cambio proporcionados por <a href="https://finexly.com">Finexly</a></p>
      </footer>
    </main>
  );
}

export default App;

Manejo de Casos Límite

Un conversor listo para producción necesita manejar varios casos límite:

  • Cantidades inválidas: Protege contra NaN verificando el resultado de parseFloat
  • Misma divisa: Añade una advertencia visual si el usuario selecciona la misma divisa de origen y destino
  • Fallos de red: El estado de error en el hook ya gestiona los fallos de API

Optimización de Rendimiento con Debouncing

Si deseas que la conversión se actualice mientras el usuario escribe, añade un hook de debounce:

// src/hooks/useDebounce.ts
import { useState, useEffect } from "react";

export function useDebounce<T>(value: T, delayMs: number): T {
  const [debouncedValue, setDebouncedValue] = useState<T>(value);

  useEffect(() => {
    const timer = setTimeout(() => setDebouncedValue(value), delayMs);
    return () => clearTimeout(timer);
  }, [value, delayMs]);

  return debouncedValue;
}

Para Ir Más Lejos

Una vez que tengas funcionando el conversor básico, aquí hay mejoras de alto valor:

  • Gráfico de tipos históricos: Combina el tipo en tiempo real con datos históricos de la API histórica de Finexly para mostrar una tendencia de 30 días
  • Conversión multidivisa: Muestra una tabla de tipos para las 10 divisas principales simultáneamente
  • Divisas favoritas: Persiste los pares de divisas preferidos del usuario en localStorage
  • Renderizado del lado del servidor con Next.js: Mueve la llamada API a un Route Handler para que tu clave API nunca se exponga al navegador

Preguntas Frecuentes

¿Cuál es la mejor API de tipos de cambio para React? Para aplicaciones React, necesitas una API REST que soporte CORS. La API de Finexly soporta CORS en todos los planes y proporciona cobertura para más de 170 divisas con un nivel gratuito.

¿Con qué frecuencia se actualizan los tipos de cambio? La API de Finexly actualiza los tipos cada 60 segundos para los planes en tiempo real y una vez al día para los planes estándar. Para la mayoría de las aplicaciones no comerciales, los tipos diarios o por hora son suficientes.

¿Puedo usar una API de divisas en una aplicación React del lado del cliente? Sí, si la API soporta CORS. La API de Finexly permite solicitudes desde el navegador en todos los planes. Sin embargo, para aplicaciones en producción, es mejor práctica enrutar las solicitudes a través de tu propio backend.

¿Cómo evito exponer mi clave API en React? Para el desarrollo, usa el archivo .env de Vite y prefija tu variable con VITE_. Para producción, enruta las solicitudes a través de un API Route de Next.js o una función serverless.

¿Cómo convierto entre dos divisas que no son USD? La API de Finexly soporta cualquier divisa base en todos los planes, lo que simplifica significativamente esto. Simplemente solicita la divisa origen como base directamente.


¿Listo para añadir tipos de cambio en tiempo real a tu aplicación React? Obtén tu clave API gratuita de Finexly — sin tarjeta de crédito. Comienza con 1.000 solicitudes gratuitas al mes y escala según crezcas.

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 →