Integrating API in a React Project can be easily done by achieving simple project structure. Let’s see how to integrate an API in a React Project.
We will be building an App to List Current Rates and Currency Convertor using Frankfurter API https://www.frankfurter.app/.
You can use any API, I found this one listed over here: GitHub - public-apis/public-apis: A collective list of free APIs for use
Let’s get started by setting up a project with [create-react-app](https://github.com/facebook/create-react-app)
.
npx create-react-app forex-app
cd forex-app
yarn start
This will initialize a new React App named forex-app
, start the local development server on port 3000
and open the URL http://localhost:3000
on the default Browser.
We will use following design for our UI: (many parts of it)
Foreign Currency Rates and Convertor Mobile App by Tim on Dribbble
The design proposes the use of Country Flags for currency symbols
As we can see in above design, there is a list of rates for the preferred currency. We will make this screen working in our design. Let’s add the screen to list the currency exchange rates for a base currency.
The API response structure for the Rates is as follows:
{
"amount": 1,
"base": "USD",
"date": "2020-05-08",
"rates": {
"AUD": 1.5321,
"BGN": 1.8037,
"BRL": 5.817,
"...": ...
}
}
For above response, following React Component will display the rates:
import * as React from "react";
import "./RateList.css";
const Amount = ({ amount, rate }) => {
const _rate = Number(rate);
return (
<span className="rate">
{(amount ? _rate * amount : _rate).toFixed(5)}
</span>
);
};
const CurrencyFlag = ({ currency }) => (
<span className={`
currency-flag
currency-flag-${currency.toLowerCase()}
`}></span>
);
const CSymbol = ({ currency }) => (
<span className="currency">{currency.toUpperCase()}</span>
);
const display = (currency, reverse) => [
<CurrencyFlag key={`flag-${currency}`} currency={currency} />,
<CSymbol key={`symbol-${currency}`} currency={currency} />,
];
const Currency = ({ currency = "usd" }) => (
<div className="currency-box">{display(currency)}</div>
);
export const RateList = ({ rates = {}, amount, className }) => (
<div className={`rate-list-container ${className || ''}`}>
<div className="rate-list">
<ul>
{Object.keys(rates).map((currency, index) => (
<li key={index}>
<Currency currency={currency} />
<Amount rate={rates[currency]} amount={amount} />
</li>
))}
</ul>
</div>
</div>
);
And apart from the list, we will need the component to select our preferred currency and set a base amount to convert. Following component will be responsible for that:
import * as React from "react";
import "./CurrencySelector.css";
import { CurrencyFlag } from "../CurrencyFlag";
const currencies = ["EUR", "USD", "GBP"];
const CurrencyFlag = ({ currency }) => (
<span className={`
currency-flag
currency-flag-${currency.toLowerCase()}
`}></span>
);
const CurrencySelector = ({ currency = "usd", onChangeCurrency }) => (
<div className="currency-box">
<select
className="currency-select"
value={currency}
onChange={(e) => onChangeCurrency(e.target.value)}
>
{currencies.map((item, index) => (
<option key={index} >{item}</option>
))}
</select>
<CurrencyFlag key={`flag-${currency}`} currency={currency} />
</div>
);
export const SearchBar = ({
currency = "usd",
amount = 1,
onChangeAmount = () => {},
onChangeCurrency = () => {},
}) => (
<div className="search-bar-container">
<div className="search-bar">
<input
type="text"
defaultValue={amount}
onChange={(e) => onChangeAmount(e.target.value)}
placeholder="Amount"
/>
<CurrencySelector
currency={currency}
onChangeCurrency={onChangeCurrency}
/>
</div>
</div>
);
Lets try to assemble the above components with some mock data:
import React, { useState } from "react";
import { SearchBar } from "../SearchBar/SearchBar";
import { RateList } from "../RateList/RateList";
const rates = {
"AUD": 1.5321,
"BGN": 1.8037,
"BRL": 5.817
}
function App() {
const [state, setState] = useState({
rates,
amount: 1,
currency: "USD",
});
const { amount, currency, rates } = state;
const updateAmount = (amount) =>
setState((currentState) => ({
...currentState,
amount: Number(amount),
}));
const updateCurrency = (currency) =>
setState((currentState) => ({
...currentState,
currency,
}));
return (
<div className="app" data-testid="app-container">
<main className="contents">
<SearchBar
amount={amount}
currency={currency}
onChangeAmount={updateAmount}
onChangeCurrency={updateCurrency}
/>
<RateList className="rates" rates={rates} amount={amount} />
</main>
</div>
);
}
export default App;
Now to fetch the rates from API we will use fetch and following will be our function to handle all the GET requests:
const baseUrl = "//api.frankfurter.app";
const request = (_url, method = "GET", body = "") => {
const url = `${baseUrl}${_url}`;
const headers = new Headers();
headers.append("Content-Type", "application/json");
const params = {
method,
headers: headers,
};
if (["POST", "PUT"].includes(method)) {
params.body = typeof body !== "string" ? JSON.stringify(body) : body;
}
const request = new Request(url, params);
return fetch(request).then((response) => {
const { status, headers } = response;
if (status === 204 || headers.get("Content-Length") === 0) {
return {};
}
return response.json();
});
};
export const getData = (url) => request(url, "GET");
export const postData = (url, data) => request(url, "POST", data);
export const putData = (url, data) => request(url, "PUT", data);
export const deleteData = (url) => request(url, "DELETE");
export default {
get: getData,
post: postData,
put: putData,
delete: deleteData,
};
With all the necessary pieces in place, we will integrate the API call with getData
function in the App
Component with the following function and it will be chained to update the state in the Component:
const getRates = (currency) => getData(
`/latest?from=${currency}`
).then(({ rates }) =>
setState((currentState) => ({
...currentState,
rates,
}))
);
And we will use the React's useEffect
hook to execute the initial fetch call:
useEffect(() => {
getRates(state.currency);
}, []);
This will call the API for Rates with fetch on the first call. But we want to fetch rates for any change in the Currency.
As we are already updating the state in the Change Handler of select
, we just need to make it; currency from state; a dependency of useEffect
.
In this way, any changes to the dependency will trigger re-execution of the useEffect
hook. The following code will do that:
const App = () => {
const [state, setState] = useState({
rates: {},
amount: 1,
currency: "USD",
});
...
useEffect(() => {
getRates(state.currency);
}, [state.currency]);
...
return (...);
}
Now, if we want to make sure of newest rates for conversion of amount as well, we will need the following changes to the getRates
function and useEffect
hook alonf with the change handlers to update the amount in state:
const App = () => {
const [state, setState] = useState({
rates: {},
amount: 1,
currency: "USD",
});
...
const getRates = (currency, amount = 1) => getData(
`/latest?from=${currency}&amount=${amount}`
).then(({ rates }) =>
setState((currentState) => ({
...currentState,
rates,
}))
);
useEffect(() => {
getRates(state.currency, state.amount);
}, [state.currency, state.amount]);
...
return (...);
}
You can play with the Code and demo at the following links:
Conclusion
Here we saw the following things:
- Starting React app with create-react-app
- Using Hooks to maintain state with
useState
- Using
fetch
in React Project -
useEffect
for reacting to state changes and make API requests
How do you call APIs in your React project?
Let me know through comments 💬 or on Twitter at @patelpankaj and @time2hack
If you find this article helpful, please share it with others 🗣
Subscribe to the blog to receive new posts right to your inbox.
Credits
- Photo by Ferenc Almasi on Unsplash
- Icons from Icon8 via Lunacy
Originally published at https://time2hack.com on May 11, 2020.
Top comments (3)
well put together! waouw! :applause:
This is just... AWESOME!!
Thanks a lot :)