javascriptreactjsjson

A simple currency converter in React does not update when the currency is changed


I am trying to build a simple currency converter in React. However, when I try to change the currencies from the drop-down, the rates do not update. I suppose it will be a problem with one of the useEffects which fetch the rates from an API. But I'm lost.

These are the errors I'm getting in the console: "react-dom.development.js:86 Warning: Received NaN for the value attribute. If this is expected, cast the value to a string." and "VM586:1 Uncaught (in promise) SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON"

My code:

App.js:

import './App.css';
import React, { useEffect, useState } from 'react';
import CurrencyRow from './CurrencyRow';

const BASE_URL = 'https://api.exchangerate.host/latest';

function App() {
  const [currencyOptions, setCurrencyOptions] = useState([]);
  const [fromCurrency, setFromCurrency] = useState();
  const [toCurrency, setToCurrency] = useState();
  const [exchangeRate, setExchangeRate] = useState();
  const [amount, setAmount] = useState(1);
  const [amountInFromCurrency, setAmountInFromCurrency] = useState(true);

  let toAmount;
  let fromAmount;

  if (amountInFromCurrency) {
    fromAmount = amount;
    toAmount = amount * exchangeRate;
  } else {
    toAmount = amount;
    fromAmount = amount / exchangeRate;
  }

  useEffect(() => {
    fetch(BASE_URL)
      .then((res) => res.json())
      .then((data) => {
        const firstCurrency = Object.keys(data.rates)[0];
        setCurrencyOptions([...Object.keys(data.rates)]);
        setFromCurrency(data.base);
        setToCurrency(firstCurrency);
        setExchangeRate(data.rates[firstCurrency]);
      });
  }, []);

  useEffect(() => {
    if (fromCurrency != null && toCurrency != null) {
      fetch(`$(BASE_URL)?base=${fromCurrency}&symbols=${toCurrency}`)
        .then((res) => res.json())
        .then((data) => setExchangeRate(data.rates[toCurrency]));
    }
  }, [fromCurrency, toCurrency]);

  function handleFromAmountChange(e) {
    setAmount(e.target.value);
    setAmountInFromCurrency(true);
  }

  function handleToAmountChange(e) {
    setAmount(e.target.value);
    setAmountInFromCurrency(false);
  }

  return (
    <>
      <h1>Convert currency</h1>
      <CurrencyRow
        currencyOptions={currencyOptions}
        selectedCurrency={fromCurrency}
        onChangeCurrency={(e) => setFromCurrency(e.target.value)}
        onChangeAmount={handleFromAmountChange}
        amount={fromAmount}
      />
      <div className="equals">=</div>
      <CurrencyRow
        currencyOptions={currencyOptions}
        selectedCurrency={toCurrency}
        onChangeCurrency={(e) => setToCurrency(e.target.value)}
        onChangeAmount={handleToAmountChange}
        amount={toAmount}
      />
    </>
  );
}

export default App;

CurrencyRow.jsx:

/* eslint react/prop-types: 0 */

import React from 'react';
import './App.css';

const BASE_URL = 'https://api.exchangerate.host/latest';

function CurrencyRow(props) {
  const {
    currencyOptions,
    selectedCurrency,
    onChangeCurrency,
    amount,
    onChangeAmount,
  } = props;

  return (
    <div>
      <input
        type="number"
        className="input"
        value={amount}
        onChange={onChangeAmount}
      />
      <select value={selectedCurrency} onChange={onChangeCurrency}>
        {currencyOptions.map((option) => (
          <option key={option} value={option}>
            {option}{' '}
          </option>
        ))}
      </select>
    </div>
  );
}

export default CurrencyRow;

Any help will be greatly appreciated! Thanks so much!


Solution

  • I couldn't fully debug your code but I think that the problem will happen in the second useEffect in the if statement.

    because the init value of fromCurrency & toCurrency is undefined but you're comparing it with null so it will fetch anyway because the value is undefined not Null

    so I think you need to change the if statement to be like that

    if (!fromCurrency || !toCurrency) {
       // do fetch and the rest here.
    }
    

    and that means that you will not make the fetch unliss you have two values. no empty strings, undefined or null is accepted.