Hackernoon logoBuild Your Own Currency Exchange Web App in ~100 lines using CRA [A Step By Step Guide] by@epranka

Build Your Own Currency Exchange Web App in ~100 lines using CRA [A Step By Step Guide]

Author profile picture

@eprankaEdvinas Pranka

Full-stack developer

This tutorial describes how to create a simple currency exchange app in just about 100 lines of code using the Create React App boilerplate.

To see it in action check out thisĀ live demo.

šŸ› ļø Preparation

First, create the react app. I call it "rates".
$ yarn create react-app rates
Run the command in your root
$ yarn start
Your web app will be available onĀ http://localhost:3000

āš“ Fetching the currencies rate

For currency exchange data we will use free API onĀ exchangeratesapi.io
We will load the latest data of the currencies rates.
Install theĀ swrĀ andĀ unfetchĀ libraries. It helps to easily fetch API.
$ yarn add swr unfetch
Create the fetcher function outside the App component
// src/App.js
import React from "react";
import "./App.css";
import fetch from "unfetch";

const API_URL = "https://api.exchangeratesapi.io";

const fetcher = async path => {
  const res = await fetch(API_URL + path);
  const json = await res.json();
  return json;
};

// function App...
AddĀ useSWRĀ in App component to fetch data
import React from "react";
import "./App.css";
import fetch from "unfetch";
import useSWR from "swr";

 // API_URL = ...

 // const fetcher = ...

 function App() {
  const { data: currencies } = useSWR("/latest?base=EUR", fetcher);

  return <div>Welcome to your Currency exchange app!</div>;
 }
Now we have the currencies rates inĀ currencies.ratesĀ variable.
To see the JSON data of currencies rates you can open the API url directly into your browser:Ā https://api.exchangeratesapi.io/latest?base=EUR
TheĀ ?base=EURĀ query is used to get all rates relative to EUR currency.

šŸ’„ Add the UI

For ui, we will use theĀ material-uiĀ design system. Install it:
$ yarn add @material-ui/core
Create the UI for our currency exchange app in theĀ AppĀ component.
// ...
import {
  Container,
  Paper,
  Grid,
  TextField,
  Select,
  MenuItem
} from "@material-ui/core";

// ...

function App() {
  const { data: currencies } = useSWR("/latest?base=EUR", fetcher);

  if (!currencies) {
    return null;
  }

  return (
    <Container className="currency-exchange-container" fixed>
      <h1>Currency exchange</h1>
      <Paper
        className="currency-exchange-paper"
        variant="outlined"
        elavation={1}
      >
        <Grid container spacing={3}>
          <Grid item xs={6}>
            <TextField type="number" />
          </Grid>
          <Grid item xs={6}>
            <TextField type="number" />
          </Grid>
          <Grid item xs={6}>
            <Select>
              <MenuItem value={"EUR"}>EUR</MenuItem>
              {Object.keys(currencies.rates).map((rate, key) => (
                <MenuItem key={key} value={rate}>
                  {rate}
                </MenuItem>
              ))}
            </Select>
          </Grid>
          <Grid item xs={6}>
            <Select>
              <MenuItem value={"EUR"}>EUR</MenuItem>
              {Object.keys(currencies.rates).map((rate, key) => (
                <MenuItem key={key} value={rate}>
                  {rate}
                </MenuItem>
              ))}
            </Select>
          </Grid>
        </Grid>
      </Paper>
    </Container>
  );
}
Now, look at the following code snippet. We create the currency selection box by iterating over all possible rates from our API data. Since we fetch rates relative to EUR, so we should manually add the EUR item, because it doesn't exist in rates object.
  <Select>
    <MenuItem value={"EUR"}>EUR</MenuItem>
    {Object.keys(currencies.rates).map((rate, key) => (
      <MenuItem key={key} value={rate}>
        {rate}
      </MenuItem>
    ))}
  </Select>
When the currencies are not loaded, we just return null, because of currencies rates is undefined at that moment.
  if (!currencies) {
    return null;
  }
Add some styles toĀ App.css
h1 {
  font-weight: 300;
  color: #636363;
  margin-bottom: 3rem;
}

.currency-exchange-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
}

.currency-exchange-paper {
  max-width: 350px;
  padding: 30px 30px 40px 30px;
}

.MuiInput-root {
  width: 100%;
}

āš™ļø Add logic

Now we add the inputs state to ourĀ AppĀ component
function App() {
  const { data: currencies } = useSWR("/latest?base=EUR", fetcher);

  const [fromValue, setFromValue] = useState(1);
  const [toValue, setToValue] = useState(1);

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

  const handleFromCurrencyChange = e => {
    setFromCurrency(e.target.value);
  };

  const handleToCurrencyChange = e => {
    setToCurrency(e.target.value);
  };

  const handleFromValueChange = e => {
    setFromValue(parseFloat(e.target.value));
  };

  const handleToValueChange = e => {
    setToValue(parseFloat(e.target.value));
  };

  if (!currencies) {
    return null;
  }

  return (
    <Container className="currency-exchange-container" fixed>
      <h1>Currency exchange</h1>
      <Paper
        className="currency-exchange-paper"
        variant="outlined"
        elavation={1}
      >
        <Grid container spacing={3}>
          <Grid item xs={6}>
            <TextField
              type="number"
              value={fromValue}
              onChange={handleFromValueChange}
            />
          </Grid>
          <Grid item xs={6}>
            <TextField
              type="number"
              value={toValue}
              onChange={handleToValueChange}
            />
          </Grid>
          <Grid item xs={6}>
            <Select value={fromCurrency} onChange={handleFromCurrencyChange}>
              <MenuItem value={"EUR"}>EUR</MenuItem>
              {Object.keys(currencies.rates).map((rate, key) => (
                <MenuItem key={key} value={rate}>
                  {rate}
                </MenuItem>
              ))}
            </Select>
          </Grid>
          <Grid item xs={6}>
            <Select value={toCurrency} onChange={handleToCurrencyChange}>
              <MenuItem value={"EUR"}>EUR</MenuItem>
              {Object.keys(currencies.rates).map((rate, key) => (
                <MenuItem key={key} value={rate}>
                  {rate}
                </MenuItem>
              ))}
            </Select>
          </Grid>
        </Grid>
      </Paper>
    </Container>
  );
}
Also, add the two following functions for currency exchange
const convertFromTo = () => {
    const fromRate =
      fromCurrency === "EUR" ? 1 : currencies.rates[fromCurrency];
    const valueInEur = fromValue / fromRate;
    const toRate = toCurrency === "EUR" ? 1 : currencies.rates[toCurrency];
    setToValue(valueInEur * toRate);
  };

  const convertToFrom = () => {
    const toRate = toCurrency === "EUR" ? 1 : currencies.rates[toCurrency];
    const valueInEur = toValue / toRate;
    const fromRate =
      fromCurrency === "EUR" ? 1 : currencies.rates[fromCurrency];
    setFromValue(valueInEur * fromRate);
  };
One function converts currencies forward, and other - backward. In both functions, firstly, we convert currencies to EUR, because all rates we fetched from API are relative to euros.
The last thing is to add the React hooks which run the rates exchange after the input change.
  useEffect(() => {
    convertFromTo();
  }, [fromValue, toCurrency]);

  useEffect(() => {
    convertToFrom();
  }, [toValue, fromCurrency]);
Here is a fullĀ App.jsĀ file
import React, { useState, useEffect } from "react";
import "./App.css";
import fetch from "unfetch";
import useSWR from "swr";
import {
  Container,
  Paper,
  Grid,
  TextField,
  Select,
  MenuItem
} from "@material-ui/core";

const API_URL = "https://api.exchangeratesapi.io";

const fetcher = async path => {
  const res = await fetch(API_URL + path);
  const json = await res.json();
  return json;
};

function App() {
  const { data: currencies } = useSWR("/latest?base=EUR", fetcher);

  const [fromValue, setFromValue] = useState(1);
  const [toValue, setToValue] = useState(1);

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

  const handleFromCurrencyChange = e => {
    setFromCurrency(e.target.value);
  };

  const handleToCurrencyChange = e => {
    setToCurrency(e.target.value);
  };

  const handleFromValueChange = e => {
    setFromValue(parseFloat(e.target.value));
  };

  const handleToValueChange = e => {
    setToValue(parseFloat(e.target.value));
  };

  const convertFromTo = () => {
    const fromRate =
      fromCurrency === "EUR" ? 1 : currencies.rates[fromCurrency];
    const valueInEur = fromValue / fromRate;
    const toRate = toCurrency === "EUR" ? 1 : currencies.rates[toCurrency];
    setToValue(valueInEur * toRate);
  };

  const convertToFrom = () => {
    const toRate = toCurrency === "EUR" ? 1 : currencies.rates[toCurrency];
    const valueInEur = toValue / toRate;
    const fromRate =
      fromCurrency === "EUR" ? 1 : currencies.rates[fromCurrency];
    setFromValue(valueInEur * fromRate);
  };

  useEffect(() => {
    convertFromTo();
  }, [fromValue, toCurrency]);

  useEffect(() => {
    convertToFrom();
  }, [toValue, fromCurrency]);

  if (!currencies) {
    return null;
  }

  return (
    <Container className="currency-exchange-container" fixed>
      <h1>Currency exchange</h1>
      <Paper
        className="currency-exchange-paper"
        variant="outlined"
        elavation={1}
      >
        <Grid container spacing={3}>
          <Grid item xs={6}>
            <TextField
              type="number"
              value={fromValue}
              onChange={handleFromValueChange}
            />
          </Grid>
          <Grid item xs={6}>
            <TextField
              type="number"
              value={toValue}
              onChange={handleToValueChange}
            />
          </Grid>
          <Grid item xs={6}>
            <Select value={fromCurrency} onChange={handleFromCurrencyChange}>
              <MenuItem value={"EUR"}>EUR</MenuItem>
              {Object.keys(currencies.rates).map((rate, key) => (
                <MenuItem key={key} value={rate}>
                  {rate}
                </MenuItem>
              ))}
            </Select>
          </Grid>
          <Grid item xs={6}>
            <Select value={toCurrency} onChange={handleToCurrencyChange}>
              <MenuItem value={"EUR"}>EUR</MenuItem>
              {Object.keys(currencies.rates).map((rate, key) => (
                <MenuItem key={key} value={rate}>
                  {rate}
                </MenuItem>
              ))}
            </Select>
          </Grid>
        </Grid>
      </Paper>
    </Container>
  );
}

export default App;

āœØ Finished!

Congratulations! You have done the currency exchange app using the CRA (Create React App).
The full source code you can find in my repositoryĀ epranka/rates.
Thanks for reading this. I hope it was helpful to you. Feedback and questions are appreciated.
Follow onĀ Twitter,Ā GitHub, and letā€™s connect onĀ LinkedIn
(Originally published here)

Tags

The Noonification banner

Subscribe to get your daily round-up of top tech stories!