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!
2
Answers
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
isundefined
but you’re comparing it with null so it will fetch anyway because the value isundefined
notNull
so I think you need to change the if statement to be like that
and that means that you will not make the fetch unliss you have two values. no empty strings, undefined or null is accepted.
The issue is when you are calling the API with fromCurrency and toCurrency. The template literal is wrong. Wrap the BASE_URL variable in curly brackets, not in parentheses. Change it to
fetch(`${BASE_URL}?base=${fromCurrency}&symbols=${toCurrency}`)
Check out this Codesandbox link
https://codesandbox.io/s/cold-sky-us38d7?file=/src/App.js