React & HTTP – Retrieving Crypto Currency Data from an API
Cryptocurrency data
With a variety of crypto currency services available at the moment there appears to be a huge demand for web applications that depict useful statistics or information relating to all things digital currency.
So I thought I’d detail how to retrieve this information and manipulate it in your own UI using React.js and create-react-app.
This post is based on an application I created called Simple Crypto Profit Calculator.
Coin API
The data source that we’ll be using is coming from Crypocompare.
This API provides us with a wide range of endpoints for getting information about crypto currencies.
Create React App
We will use create-react-app in order to install a base project that is already configured.
If you haven’t heard of create react app before. It provides a template application with all our Webpack and Babel compilers options predefined. It saves you from time-consuming setup and configuration.
The documentation for it is quite detailed so you can add and remove options are you see fit.
To initialise a project run:
npx create-react-app crypto-app
cd crypto-app
npm start
Axios
We will be using the HTTP library Axios to make our data requests to CryptoCompare.
Simply install it with the command:
npm install axios
And import it into the top of the file:
import axios from 'axios';
Coin Type
We want to create a home.jsx
file and inside our render()
function we will create form input elements that the user will interact with.
import * as React from 'react'; class Home extends React.Component { constructor(props) { super(props); this.state = {}; } render() { return (); } } export default Home; Enter Previous Purchase
Theres nothing unusual here, just form based JSX markup using bootstrap columns for the layout of the grid.
We then want to define the state of our home component. In order to determine this accurately we need to ask what is likely to change in our UI?
Well, we have 3 different types of input fields so we can be sure we need state values for the currently selected value of each field.
We also need a default start date for the date picker field.
constructor(props) { super(props); this.state = { selectedSymbol: '', selectedCoinType: '', selectedPrice: '', coinNames: [], isLoading: true, startDate: moment(), coinTypes: [], coinSymbols: [], }; }
We also want the state to track an isLoading
boolean value in order to determine when our application is processing a http request.
So our first input field will be a list of coin types:
We want to use the CoinList endpoint that the CryptoCompare API provides for us. This will retrieve the list of coin types and populate our select dropdown field.
But when exactly do we want this coin dropdown field to be populated? Well, ideally we want this to happen when the component is being initialised or when it has just mounted.
We can use the React’s lifecycle method onComponentDidMount()
for this purpose.
componentDidMount(){ this.getCoinTypes(); }
Our logic inside getCoinTypes()
will use our HTTP library Axios in order to hit the endpoint that retrieves all the coin types that we need.
We also want to populate the dropdown with a list of full coin names and not just their symbols. For example, the name Bitcoin instead of BTC. This will be more clear for the user when he/she is searching for their desired coin. So we define two different arrays here:
getCoinTypes(){ let coins = []; let coinNames = []; }
And then our HTTP request using the Axios library:
getCoinTypes(){ let coins = []; let coinNames = []; axios.get('https://www.cryptocompare.com/api/data/coinlist/') }
This is a Promise that will return a full list of coins from the API.
Here is the full list of possible properties from this data:
From this response we then want to get all possible coin names from this list using .then()
:
.then( (response) => { Object.keys(response.data.Data).forEach(function(key) { coins.push(response.data.Data[key]); });
Our coins
array now contains a full list of coin objects retrieved from the endpoint.
We now want to iterate through this and return only the coin names:
coins.forEach(element => { coinNames.push(element.CoinName); });
CoinName
refers to a property that we want of the data being returned.
And to be user friendly we want to sort them alphabetically:
coinNames.sort();
We now want the UI to reflect this data so we use this.setState({})
in order to re-render the UI and apply these new changes from the API call.
this.setState({ coinNames: coinNames, coinTypes: coins, isLoading: false, selectedSymbol: coinNames[0] });
We also want to have catch method in case something goes wrong with our API call. So the getCoinTypes
method should look like this in full:
getCoinTypes(){ let coins = []; let coinNames []; axios.get('https://www.cryptocompare.com/api/data/coinlist/') .then( (response) => { Object.keys(response.data.Data).forEach(function(key) { coins.push(response.data.Data[key]); }); coins.forEach(element => { coinNames.push(element.CoinName); }); coinNames.sort(); this.setState({ coinNames: coinNames, coinTypes: coins, selectedSymbol: coinNames[0] }); console.log(coins); }) .catch(function (error) { console.log(error); }); }
Our state should be applied in our markup:
{ this.onPriceChange(e); }} type="text" name="price" />
A JSX ternary operator is used here to ensure that coinTypes exists if not null is returned:
{this.state.coinTypes ? this.state.coinNames.map( (coin, index) => { return (); }) : null }
When the user changes the value we want to track this, so we set the state to the newly changed value:
onChange={(e) => this.onSymChange(e)}
onSymChange(e){ this.setState({ selectedSymbol: e.target.value }); }
Date Picker
We want the user to pick a date from a calendar. This is made quite easy by an external React.js component called React DatePicker
To install this run the command:
npm i react-datepicker
Import it into the top of our component:
import DatePicker from 'react-datepicker';
And use it for our date field:
this.handleChange(date)} />;
The date shown will be based on the state value startDate
. We have set the default value of this to todays date.
When it will change we simply run the function handleChange(date)
which will set our state to the newly selected value:
handleChange(date: Moment){ this.setState({ startDate: date }); }
Using these simple steps we will have created a user friendly date picker that is tracked by our state, which is great. This is a common experience when working with React.
- You find that you need a certain piece of utility be it something form related or otherwise.
- You look up to see if a package exists to solve this problem (there tends to be always something available for the problem your trying to solve).
- You then import this piece of utility as a component and use predefined props for interacting with it.
Loading
But hold on, depending on the speed of the network the input field might not fully initialised which can be a problem for the user.
We need to show a loading spinner until the http request is done.
Fortunately, this is actually quite straight forward process. Simply install a spinner library such as ReactSpinners:
npm install react-spinners
Import your spinner of choice at the top of file:
import { ClipLoader } from 'react-spinners';
And use a ternary operator to show it while the state isLoading is equal to true:
{this.state.isLoading ?: // form markup
What Next?
So we have a populated dropdown menu of coin types and provided a datepicker. What can the user do from here? Well, in a second part I will detail how we can use what the user has inputed to retrieve his/her desired information about a coin type.