Help with Build a Currency Converter App

index.jsx

const { useState, useMemo, useCallback } = React;

const exchangeRateMapping = {
    "USD": 1,
    "EUR": 0.86,
    "GBP": 0.74,
    "JPY": 148.46
  };

export function CurrencyConverter() {

  const [amount,setAmount] = useState(1);

  const [fromCurrency,setFromCurrency] = useState("USD");

  const [toCurrency,setToCurrency] = useState("EUR");

  const baseAmount = useMemo(() =>{

    console.log(`baseAmount is running`);

    const base = amount/exchangeRateMapping[fromCurrency];

  return base;

  },[amount,fromCurrency]);

  const finalAmount = useMemo(() =>{

    console.log(`finalAmount is running`);

    const final = baseAmount*exchangeRateMapping[toCurrency];

    return final

  },[toCurrency,baseAmount]);

  return (
    <div id="container">
      <h1>Currency Converter</h1>
      <div id="amount-container">
        <label htmlFor="amount-input">
        Convert : <input id="amount-input" type="number" value={amount} onChange={(e)=>setAmount(e.target.value)} />
        </label>
      </div>
      <div id="from-currency-container">
        <label htmlFor="from-currency"> 
        From : <select value={fromCurrency} onChange={(e)=>setFromCurrency(e.target.value)}> 
        {Object.keys(exchangeRateMapping).map(currency=>(
          <option key={currency} value={currency}>{currency}</option>
        ))}
        </select>
        </label>
      </div>
      <div id="to-currency-container">
        <label htmlFor="to-currency"> 
        To : <select value={toCurrency} onChange={(e)=>setToCurrency(e.target.value)}> 
        {Object.keys(exchangeRateMapping).map(currency=>(
          <option key={currency} value={currency}>{currency}</option>
        ))}
        </select>
        </label>
      </div>
      <div id="results">
        <p>Converted Amount : {finalAmount.toFixed(2)} {toCurrency}</p>
      </div>
    </div>
  )

}


index.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <title>Currency Converter</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.5/babel.min.js"></script>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      src="index.jsx"
    ></script>
    <link rel="stylesheet" href="styles.css" />
</head>

<body>
    <div id="root"></div>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      data-presets="react"
      data-type="module"
    >
      import { CurrencyConverter } from './index.jsx';
      ReactDOM.createRoot(document.getElementById('root')).render(<CurrencyConverter />);
    </script>
</body>

</html>
no css

Edit: no css

I am failing test cases

  • 5. Changing the value of the first select element should cause the converted amounts to be recalculated.

  • 6. Changing the value of the second select element should not cause the converted amounts to be recalculated.

though I’m not sure why. With the console.log() statements, it seems like the code should pass the test case.

Any help would be appreciated! Thanks very much.

please share a link to the challenge

Bump, sorry, I’m still facing problems passing these test cases, could anyone give me any pointers?

Thanks.

Please be patient and don’t bump like this.

do you have any updates? have you tried any more debugging?

please add more information to bring your topic back up, instead of just bumping

const { useState, useMemo } = React;

index.jsx

const exchangeRateMapping = {
    "USD": 1,
    "EUR": 0.86,
    "GBP": 0.74,
    "JPY": 148.46
  };

export function CurrencyConverter() {

  const [amount,setAmount] = useState(1);

  const [fromCurrency,setFromCurrency] = useState("USD");

  const [toCurrency,setToCurrency] = useState("EUR");

  const calcBase = useMemo(() =>{

    console.log(`Base is being calculated`);

    const converted = amount/exchangeRateMapping[fromCurrency];

    console.log(`Converted : ${converted}`);

    return converted

  },[amount,fromCurrency]);

  const calcFinal = useMemo(() =>{

    console.log(`Final is being calculated`);

    const final = calcBase*exchangeRateMapping[toCurrency];

    console.log(`Final : ${final}`);

    return final;
    

  },[toCurrency,calcBase]);

  return (
    <div id="container">
      <h1>Currency Converter</h1>
      <div id="amount-container">
        <label htmlFor="amount-input">
        Convert : <input id="amount-input" type="number" value={amount} onChange={
          (e)=>{setAmount(e.target.value)
          console.log("amount changed")
        }} />
        </label>
      </div>
      <div id="from-currency-container">
        <label htmlFor="from-currency"> 
        From : <select id="from-currency" value={fromCurrency} onChange={
        (e)=>{setFromCurrency(e.target.value)
        console.log("from-currency changed")}
        }> 
        {Object.keys(exchangeRateMapping).map(currency=>(
          <option key={currency} value={currency}>{currency}</option>
        ))}
        </select>
        </label>
      </div>
      <div id="to-currency-container">
        <label htmlFor="to-currency"> 
        From : <select id="to-currency" value={toCurrency} onChange={
        (e)=>{setToCurrency(e.target.value)
        console.log("to-currency changed")}
        }>
        {Object.keys(exchangeRateMapping).map(currency=>(
          <option key={currency} value={currency}>{currency}</option>
        ))}
        </select>
        </label>
      </div>
      <div id="results">
        <p>Converted Amount : {calcFinal.toFixed(2)} {toCurrency}</p>
      </div>
    </div>
  )

}


Okay, sorry for bumping, I’ll try to explain what I have done.

I have done some debugging on my jsx code by putting in some console.log(). The test cases I am failing is

5. Changing the value of the first select element should cause the converted amounts to be recalculated

6. Changing the value of the second select element should not cause the converted amounts to be recalculated.

The test case wants us to use the useMemo hook to store the results of the value of the select elements and recalculate the converted amounts only when the value of the first select element is changed.

const calcBase = useMemo(() =>{

    console.log(`Base is being calculated`);

    const converted = amount/exchangeRateMapping[fromCurrency];

    console.log(`Converted : ${converted}`);

    return converted;

  },[amount,fromCurrency]);

  const calcFinal = useMemo(() =>{

    console.log(`Final is being calculated`);

    const final = calcBase*exchangeRateMapping[toCurrency];

    console.log(`Final : ${final}`);

    return final;
    
  },[toCurrency,calcBase]);

These are my functions to calculate the converted amount in calcBase and to calculate the final amount in calcFinal respectively.

In my functions, I first use the useMemo hook to state that I want React to memoize the results of these functions and only re-run the function when the dependencies change, which are -

  • calcBase : amount (of currency) and fromCurrency, which are values that the user can input in the DOM and stored in their States
  • calcFinal : toCurrency and calcBase (because if the original currency or amount changes then final currency will have to change as well)

The logic for my functions are similar. Use the formula to calculate the converted/final amounts of currencies, and return the results of the formulas. These results are stored in the React cache.

Upon running my code, I have some console.log() statements to show:

  1. When amount changes, calcBase is run, which causes calcFinal to run, and the final result to be updated and shown in the DOM
  2. When fromCurrency changes, calcBase is run, calcFinal runs, final result to be updated and shown in the DOM
  3. When toCurrency changes, only calcFinal runs, and using the memoized converted currency to calcualte the final result which is updated and shown

This shows that my code should be conforming with the expected behaviour and test cases 5 and 6.

But my code is failing, and I’m not sure why, which is why I’m asking here in the forum.

Any help would be much appreciated, thanks for taking the time to read this.

Thank you

Don’t focus on the tests. Focus on the instructions.

  1. Your CurrencyConverter component should memoize the calculation of the converted amounts for the from currency such that a change in the to select option will not recalculate the converted amounts.

Read this very carefully.

The instruction is asking you to memoize 1 calculation, but you have useMemo twice in your code. Can you identify where “the calculation of the converted amounts” is happening?

such that a change in the to select option will not recalculate the converted amounts.

Meaning also that changing the “from” should not be memoized (should be the only time it’s reclaculted). Can you explain how the dependency array works for useMemo?

Oh, okay. Thanks for the reply. So I understood from your response that I did not need to use two useMemo hooks to memoize the results from each part of the calculation, and the test case is only expecting one useMemo hook. The way I solved it is I think perhaps not the expected method(?) because I changed one of the useMemo functions into a useEffect that runs every render to update one of the results of the calculations, and that passed the test case. I understand how the dependency array works for useMemo. The dependency array tells React that I only want the function to run again when the values of the items in the dependency array changes. I hope that I showed you that I do understand how useMemo works and didn’t just try to “hack” the testcase to pass.

Your CurrencyConverter component should memoize the calculation of the converted amounts for the from currency such that a change in the to select option will not recalculate the converted amounts.

The way that I understood this instruction is that you should use the useMemo hook to memoize the results of the calculations. It is not explicity stated that only one useMemo should be used, and I thought that the freedom to use the React hooks that I was taught was up to my discretion. Hence in my original solution I used two useMemos.

Thanks for your reply in guiding me towards the solution. Appreciate it.

I think breaking up the calculation into two different functions wasn’t necessary and does make the memorization a bit more complicated.

My solution was similar to yours but I do the calculation in one line (something like amount / exchangeRateMapping[fromCurrency] * exchangeRateMapping[toCurrency]; (You should have spaces around your operators to make it easier to read))

Also I only have from in my dependency array. If I add amount into my array it still passes and that’s again more similar to your solution.

I see. Thanks for the insights.