Hello Developers,
This app is my new react project to learn about state + axios + routes in react js. It shows the exchage rates and convert currency value from one to other. I have used following packages to create this app...
- Axios
- React Router Dom
- React Bootstrap + Bootstrap
Use npm install and npm start to run this project
So to create this app, I have used following code.
App.js
import "bootstrap/dist/css/bootstrap.min.css"; import "./App.css"; import Navigation from "./components/shared/Navigation"; import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import CurrencyConverter from "./pages/CurrencyConverter"; import CurrencyRates from "./pages/CurrencyRates"; function App() { return ( <div className="App"> <Router> <Navigation /> <div className="container"> <Routes> <Route path="/" element={<CurrencyRates />} /> <Route path="/currency-converter" element={<CurrencyConverter />} /> </Routes> </div> </Router> </div> ); } export default App; To style loader in this app, update App.css to following...
.loadingSpinnerContainer { position: fixed; top: 0; right: 0; bottom: 0; left: 0; background-color: rgba(0, 0, 0, 0.5); z-index: 5000; display: flex; justify-content: center; align-items: center; } .loadingSpinner { width: 64px; height: 64px; border: 8px solid; border-color: #00cc66 transparent #00cc66 transparent; border-radius: 50%; animation: spin 1.2s linear infinite; } Now we need to created pages to load currency exchange rates and converter. So i created pages folder in src. Add following files in pages folder.
pages/CurrencyConverter.jsx
import React, { useEffect, useState } from 'react' import http from '../components/CustomAxios' import Spinner from '../components/shared/Spinner'; function CurrencyConverter() { const [symbols, setSymbols] = useState([]); const [loading, setLoading] = useState(false); const [fromCurrency, setFromCurrency] = useState(''); const [toCurrency, setToCurrency] = useState(''); const [amount, setAmount] = useState(0); const [convertedAmount, setConvertedAmount] = useState(null); useEffect(() => { setLoading(true); const getSymbols = async () => { const sys = await http.get("/symbols"); const data = await sys.data; let arr = Array.from(Object.keys(data.symbols), k => [`${k}`, data.symbols[k]]); setSymbols(arr); setLoading(false); }; getSymbols(); }, []); const handleSubmit = async (e) => { e.preventDefault(); setLoading(true); const res = await http.get('/convert?from=' + fromCurrency + '&to=' + toCurrency + "&amount=" + amount + "&places=2"); const data = await res.data; //console.log(data); setConvertedAmount(data.result); setLoading(false); } const handleSelectChange = (e) => { setConvertedAmount(null); if(e.target.id === 'toCurrency'){ setToCurrency(e.target.value); } if(e.target.id === 'fromCurrency'){ setFromCurrency(e.target.value); } } if (loading) { return <Spinner /> } return ( <> <h1>Convert Currency</h1> <form onSubmit={handleSubmit}> <table className='table table-borderless table-hover'> <tbody> <tr> <td width="30%">From Currency</td> <td width="70%"> <select className='form-control' id="fromCurrency" onChange={handleSelectChange}> {symbols.length > 0 && symbols.map((item) => ( <option value={item[0]} key={item[1].code}>{item[1].code} - {item[1].description}</option> ))} </select> </td> </tr> <tr> <td>To Currency</td> <td> <select className='form-control' id="toCurrency" onChange={handleSelectChange}> {symbols.length > 0 && symbols.map((item) => ( <option value={item[0]} key={item[1].code}>{item[1].code} - {item[1].description}</option> ))} </select> </td> </tr> <tr> <td>Amount</td> <td><input className='form-control' type="number" onChange={(e) => setAmount(e.target.value)} /></td> </tr> </tbody> <tfoot> <tr> <td> </td> <td><button className='btn btn-primary' type="submit">Convert</button></td> </tr> {convertedAmount !== null && <tr> <td>Converted Amount</td> <td>{toCurrency} {convertedAmount}</td> </tr> } </tfoot> </table> </form> </> ) } export default CurrencyConverter pages/CurrencyRates.jsx
import React, { useEffect, useState } from 'react' import ExchangeRate from '../components/ExchangeRate' import http from '../components/CustomAxios' function CurrencyRates() { const [rates, setRates] = useState([]); const [baseCurrency, setBaseCurrency] = useState('Eur'); const [loading, setLoading] = useState(true); const [exchangeDate, setExchangeDate] = useState(''); useEffect(() => { const getRates = async () => { const response = await http.get('/latest?places=2'); const data = await response.data; //console.log(data); let arr = Array.from(Object.keys(data.rates), k => [`${k}`, data.rates[k]]); //console.log(arr); setRates(arr); setLoading(false); setBaseCurrency(data.base); setExchangeDate(data.date); } getRates(); }, []) return ( <> <h1>Daily Exchange Rates</h1> <div className='text-bold'> <span className='float-start'><strong>Base Currency: {baseCurrency}</strong></span> <span className='float-end'><strong>Date: {exchangeDate}</strong></span> <br /> </div> <ExchangeRate rates={rates} loading={loading} /> </> ) } export default CurrencyRates Now we create some components in src/components folder. First is to initlize the axios with base url. I am using "exchangerate.host" website API's for currency services app.
components/CustomAxios.js
import axios from "axios"; const http = axios.create({ baseURL: 'https://api.exchangerate.host' }); export default http; Next we create ExchangeRate.jsx file to show all rates from api.
components/ExchangeRate.jsx
import React from 'react' import Spinner from './shared/Spinner'; function ExchangeRate({ rates, loading }) { if (loading) { return <Spinner/>; } const listing = rates.length > 0 && ( <div className="row row-cols-5 mt-3"> {rates.map(item => ( <div className="col mt-3 mb-1" key={item[0]}> <div className="card bg-dark"> <div className="card-body"> <div className="card-text text-white"> {item[0]} - {item[1]} </div> </div> </div> </div> ))} </div> ) return ( <> {listing} </> ); } export default ExchangeRate Now to load navigation and spinner, create new folder in src/components named "shared" and in src named src/assets. For loader image, you can use any image name in src/assets folder. I've used 'loadeing.gif' name. Update your image name in spinner component
components/shared/Spinner.jsx
import React from 'react' import spinner from "../../assets/loading.gif"; function Spinner() { return ( <div className='loadingSpinnerContainer'> <img src={spinner} alt="Loading..." width="200px" height="200px" /> </div> ) } export default Spinner components/shared/Navigation.jsx
import React from 'react' import { Container, Nav, Navbar, NavDropdown } from 'react-bootstrap' import { NavLink } from 'react-router-dom' function Navigation() { return ( <Navbar bg="dark" variant="dark" expand="lg"> <Container> <Navbar.Brand href="#home">Currency Services</Navbar.Brand> <Navbar.Toggle aria-controls="basic-navbar-nav" /> <Navbar.Collapse id="basic-navbar-nav"> <Nav className="me-auto"> <NavLink className="nav-link" to="/">Home</NavLink> <NavLink className="nav-link" to="/currency-converter">Currency Converter</NavLink> {/** <NavDropdown title="Dropdown" id="basic-nav-dropdown"> <NavDropdown.Item href="#action/3.1">Action</NavDropdown.Item> <NavDropdown.Item href="#action/3.2">Another action</NavDropdown.Item> <NavDropdown.Item href="#action/3.3">Something</NavDropdown.Item> <NavDropdown.Divider /> <NavDropdown.Item href="#action/3.4">Separated link</NavDropdown.Item> </NavDropdown> */} </Nav> </Navbar.Collapse> </Container> </Navbar> ) } export default Navigation You can get the full source code at following location.
https://bitbucket.org/deepaksinghkushwah/currencyservices/src/master/
Hope you like this app.
Top comments (0)