DEV Community

Cover image for Build a Dogecoin Price Ticker using React
Nitin Ranganath
Nitin Ranganath

Posted on • Originally published at thesmartcoder.dev

Build a Dogecoin Price Ticker using React

Projects. We all love them. Especially the ones that really help us to nail down the fundamentals and learn something new. Dogecoin has been trending since the past week so why don't we build something related to it.

In this project, we will be building a simple Dogecoin price ticker, a web app which will fetch the lowest price of the day, the highest price of the day and the last traded price via an API and will be updated every 10 seconds. Throughout the project, you will learn about setting up a React project, building components, props, state and the most used React hooks such as useState and useEffect.

Dogecoin Price Ticker Demo

I've broken down the project into small sections and if you face any issues in following along, you can check the GitHub repo commits to look at the changes I've made.

Live Demo: https://dogecoin-ticker.netlify.app/
Source Code:

GitHub logo itsnitinr / dogecoin-ticker

A live Dogecoin price ticker built using React

Creating a React Project

The first step is to create ourselves a React project. For this purpose, we'll be using Create React App which will help us to focus on our code and not worry about setting up the build tools. The prerequisites are that you'll need NodeJS v8.10 or above and NPM version v5.6 or above.

Open up your terminal and run the following command in your preferred directory:

npx create-react-app dogecoin-ticker
Enter fullscreen mode Exit fullscreen mode

npx is a package runner tool that comes with npm. The above command might take 5-10 minutes to complete so grab a cup of coffee and relax!

Once done, let's hop on to the project directory. For that, you could either use the file explorer or use the following terminal command: cd dogecoin-ticker. Now, open up the project folder using your favourite text editor and we'll get started with the initial setup in the next section. To start the development server, run npm start on your terminal in the project folder.

If you got stuck in any of the steps, check this commit.

Initial Setup

Once we start our development server using npm start, go to localhost:3000 on your browser and you'll be greeted with a screen like this.

CRA Demo

This is the default homepage that Create React App has generated for us. Since we don't need anything similar to this, let's start by deleting unwanted files and setting up the project as per our requirements.

The folder structure at this moment looks something like this:

dogecoin-ticker
- public
    - index.html
    - favicon.ico
    - logo192.png
    - logo512.png
    - manifest.json
    - robots.txt
- src
    - App.css
    - App.js
    - App.test.js
    - index.css
    - index.js
    - logo.svg
    - reportWebVitals.js
    - setupTests.js
- node_modules
- .gitignore
- package.json 
- package-lock.json (or yarn.lock if using yarn)
Enter fullscreen mode Exit fullscreen mode

The public folder consists consists of our index.html file which will be rendered by our browser. Open it up and start by removing the unwanted comments and modifying the title of the webpage. You can also additionally edit the meta tag for description and add your own. Here's how your index.html should look like once you're done:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Live dogecoin price ticker built using React"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>Dogecoin Ticker</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

To give a more personal touch to our website, I have also changed the favicon and logo images which you can download from here

Let's move on to the src folder. We can get rid of most of the files here such as App.test.js, logo.svg, reportWebVitals.js and setupTests.js. On saving, you might have noticed that our development server throws an error that it failed to compile. Since we deleted the above files, we need to fix the imports as well. Checkout this commit to see the additions and deletions in detail. Our final result will look like this:

App.js

import './App.css';

const App = () => {
  return (
    <div>
      <h1>Dogecoin Ticker</h1>
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

We removed all the existing content generated by Create React App and replaced it with a div containing an h1 with the text 'Dogecoin Ticker'. I've also changed the function to an arrow function but that's not mandatory. This function returns some JSX which is rendered by React. It can be used in multiple places in our project and is known as a component.

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);
Enter fullscreen mode Exit fullscreen mode

Here, we've removed the import for reportWebVitals since we deleted it as it was not necessary. We import the React and ReactDOM libraries which allow us to render a React component onto the DOM. The React component that we're rendering here is the App component from App.js.

App.css & index.css

In these files, we just remove all the preexisting styles that were generated. Essentially, these are just empty CSS files for now but we'll add some custom styles soon.

At the end of this section, our website looks something like this:

Section 2 Demo

Making It Look Pretty

Since we're just rendering a div and an h1 currently through the App component currently, our design looks plain. To spice it up, let's add a logo (which you can download from here) and some styles. Move the logo.png to the src folder once downloaded.

Begin with importing our logo into our App.js file like this:

import logo from './logo.png'
Enter fullscreen mode Exit fullscreen mode

Now, let's add more content to our App component such as a title and a subtitle. You can use HTML elements like h1 and h5 for this purpose. To use our imported logo as the source for the img tag, we use {logo}. We can use simple JavaScript expressions and variables inside the {} to render dynamic content.

For the purpose of styling, we can add classNames to the HTML entity. We do not use class since it can be misinterpreted as a JavaScript class (OOP concept). We can target these classes in our App.css file to style them. Here's how my App.js and App.css files look like:

App.js

import logo from './logo.png';
import './App.css';

const App = () => {
  return (
    <div className="App">
      <img src={logo} width={150} height={150} alt="Dogecoin Logo" />
      <h1 className="title">Live Dogecoin Price</h1>
      <h5 className="subtitle">Dogecoin To The Moon 🚀🌕</h5>
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

App.css

.App {
  background-color: #fff3b2;
  background-image: url("data:image/svg+xml,%3Csvg width='180' height='180' viewBox='0 0 180 180' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M81.28 88H68.413l19.298 19.298L81.28 88zm2.107 0h13.226L90 107.838 83.387 88zm15.334 0h12.866l-19.298 19.298L98.72 88zm-32.927-2.207L73.586 78h32.827l.5.5 7.294 7.293L115.414 87l-24.707 24.707-.707.707L64.586 87l1.207-1.207zm2.62.207L74 80.414 79.586 86H68.414zm16 0L90 80.414 95.586 86H84.414zm16 0L106 80.414 111.586 86h-11.172zm-8-6h11.173L98 85.586 92.414 80zM82 85.586L87.586 80H76.414L82 85.586zM17.414 0L.707 16.707 0 17.414V0h17.414zM4.28 0L0 12.838V0h4.28zm10.306 0L2.288 12.298 6.388 0h8.198zM180 17.414L162.586 0H180v17.414zM165.414 0l12.298 12.298L173.612 0h-8.198zM180 12.838L175.72 0H180v12.838zM0 163h16.413l.5.5 7.294 7.293L25.414 172l-8 8H0v-17zm0 10h6.613l-2.334 7H0v-7zm14.586 7l7-7H8.72l-2.333 7h8.2zM0 165.414L5.586 171H0v-5.586zM10.414 171L16 165.414 21.586 171H10.414zm-8-6h11.172L8 170.586 2.414 165zM180 163h-16.413l-7.794 7.793-1.207 1.207 8 8H180v-17zm-14.586 17l-7-7h12.865l2.333 7h-8.2zM180 173h-6.613l2.334 7H180v-7zm-21.586-2l5.586-5.586 5.586 5.586h-11.172zM180 165.414L174.414 171H180v-5.586zm-8 5.172l5.586-5.586h-11.172l5.586 5.586zM152.933 25.653l1.414 1.414-33.94 33.942-1.416-1.416 33.943-33.94zm1.414 127.28l-1.414 1.414-33.942-33.94 1.416-1.416 33.94 33.943zm-127.28 1.414l-1.414-1.414 33.94-33.942 1.416 1.416-33.943 33.94zm-1.414-127.28l1.414-1.414 33.942 33.94-1.416 1.416-33.94-33.943zM0 85c2.21 0 4 1.79 4 4s-1.79 4-4 4v-8zm180 0c-2.21 0-4 1.79-4 4s1.79 4 4 4v-8zM94 0c0 2.21-1.79 4-4 4s-4-1.79-4-4h8zm0 180c0-2.21-1.79-4-4-4s-4 1.79-4 4h8z' fill='%23676659' fill-opacity='0.13' fill-rule='evenodd'/%3E%3C/svg%3E");
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.title {
  margin-top: 1.5rem;
  font-size: 3.5rem;
  color: #222831;
}

.subtitle {
  margin-top: 0.5rem;
  font-size: 1.5rem;
  color: #393e46;
}
Enter fullscreen mode Exit fullscreen mode

For styling, I kept the minimum height as 100vh so that the whole screen is utilised. On top of that, I've added a pale yellow color as background. The background-image property generates a diamond shaped pattern whose code I got from https://www.heropatterns.com/. Lastly, I've gave the div the display property of flex and aligned the content to be horizontally and vertically centered. Feel free to copy paste the CSS code.

I also imported the Raleway font from Google Fonts and applied some basic style reset to the index.css file.

index.css

@import url('https://fonts.googleapis.com/css2?family=Raleway:wght@400;700&display=swap');

*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: Raleway, sans-serif;
}
Enter fullscreen mode Exit fullscreen mode

Here's how our website looks like now:

Post Design Demo

We're getting there! If you found any difficulty, refer this commit.

Building Price Card Component

To display the prices of Dogecoin, you might have noticed that I've used a card-like component. This is a custom React component and in this section, we'll be building just that. Components are highly useful when we want the same layout but with with different content. Instead of writing the HTML code for each card, I can build a component which can take the price as a prop and render the content dynamically. Time to show it in action.

While component file can be created in the src folder itself, it is common practice to create a new folder inside src called components so that all our React components are at the same place and our src folder doesn't become too crowded. So, create a components folder inside the src folder. Inside the newly created components folder, let's create a new file called PriceCard.jsx for our custom component.

We can use either js or jsx extension for components. Both would work perfectly fine and hence, I'm going to use the .jsx extension this time. The price card component is just a styled div which takes consists of the type of price (highest of the day, lowest of the day or last traded price) and the price itself as props. Since the price and price type will be different for each card, we can leverage props to make our price card dynamic.

Here's how I did it:

PriceCard.jsx

const PriceCard = ({ type, price }) => {
  const border = {
    high: '8px solid #f44336',
    low: '8px solid #4caf50',
    current: '8px solid #3f51b5',
  };

  return (
    <div className="price-card" style={{ borderBottom: border[type] }}>
      <h4 className="price-type">{type}</h4>
      <h1 className="price">$ {price}</h1>
    </div>
  );
};

export default PriceCard;
Enter fullscreen mode Exit fullscreen mode

Firstly, we destructure the type and price props which will be used to make the content of price card dynamic. For styling the bottom border dynamically (red border for highest of the day, green border for the lowest of the day and blue border for last traded price), I have a created an object with 3 keys: high, low and current. The type prop will also be one of these values. By adding the style attribute to the div, the bottom border style has been made dynamic.

{{borderBottom: border[type]}} will evaluate to either borderBottom: 8px solid #f44336 , borderBottom: 8px solid #4caf50 or borderBottom: 8px solid #3f51b5. Notice that we camel case instead of the usual kebab case. For outputting dynamic content in our JSX, we wrap it with {} such as {price}.

Now that we have built and exported our custom PriceCard component, let's import it into our App component and use it.

App.js

import PriceCard from './components/PriceCard';
import logo from './logo.png';
import './App.css';

const App = () => {
      <img src={logo} width={150} height={150} alt="Dogecoin Logo" />
      <h1 className="title">Live Dogecoin Price</h1>
      <h5 className="subtitle">Dogecoin To The Moon 🚀🌕</h5>
      <div className="prices-container">
        <PriceCard type="low" price={100} />
        <PriceCard type="high" price={200} />
        <PriceCard type="current" price={150} />
      </div>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Since we don't have the prices retrieved from the API yet, I have set some random price to the price attribute. I've also wrapped all the PriceCard components in a div which we'll be using for styling.

Append the following styles to App.css:

.prices-container {
  max-width: 1200px;
  padding: 3rem 0;
  display: flex;
  justify-content: space-evenly;
  align-items: center;
}

.price-card {
  background: #fbf6f0;
  margin: 0 2rem;
  padding: 1rem 2rem;
  border-radius: 8px;
}

.price-type {
  text-transform: uppercase;
  letter-spacing: 3px;
  color: #393e46;
  margin-bottom: 1rem;
}

.price {
  color: #222831;
  font-size: 3rem;
}
Enter fullscreen mode Exit fullscreen mode

Once you have completed the above steps, you will be able to see something like:

Price Card Demo

Here's the commit for above changes in case you faced any issues.

Getting Dogecoin Price From API

Onto the final part of this project, which is to fetch the highest price of the day, lowest price of the day and last traded price from an API. This is also a great time to introduce you to React Hooks. We'll be using the useState and useEffect hook in this section.

The API that we'll be using is the WazirX API, which is a free API that allows us to get the price of lots of cryptocurrencies. The endpoint for fetching the price of Dogecoin compared to US Dollar is https://api.wazirx.com/api/v2/tickers/dogeusdt. This returns a JSON with all the data we need. However, to avoid issues due to CORS, use this endpoint: https://nitinr-cors.herokuapp.com/https://api.wazirx.com/api/v2/tickers/dogeusdt

The response from looks like this:

{
  "at": 1612629617,
  "ticker": {
    "buy": "0.05",
    "sell": "0.05001",
    "low": "0.0447283",
    "high": "0.0517549",
    "last": "0.05",
    "vol": "19364432.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Also, we will be using axios to make a GET request to the above endpoint. We need to install axios before we can begin to use it. So, stop the React development server by pressing Ctrl + C. Now type npm install axios and run the command. Once done, start the server back using npm start.

Since the price of Dogecoin is subject to change every time we make an API call, we can keep it in the state using the useState hook. Whenever the API is called, we can set the state to the newly fetched data so that our application can re-render accordingly.

Using the useEffect hook, we can make a call to our API as soon as our component is mounted. With the help of setInterval function, we can call a function, which in turn calls our API every 10 seconds. Here's the complete App.js component followed by the explanation:

App.js:

import axios from 'axios';
import { useState, useEffect } from 'react';
import PriceCard from './components/PriceCard';
import logo from './logo.png';
import './App.css';

const App = () => {
  const [ticker, setTicker] = useState({
    low: 0,
    high: 0,
    last: 0,
  });

  useEffect(() => {
    async function getDogecoinPrice() {
      const { data } = await axios.get(
        'https://nitinr-cors.herokuapp.com/https://api.wazirx.com/api/v2/tickers/dogeusdt'
      );
      setTicker(data.ticker);
    }
    getDogecoinPrice();
    const interval = setInterval(() => getDogecoinPrice(), 10000);
    return () => {
      clearInterval(interval);
    };
  }, []);

  return (
    <div className="App">
      <img src={logo} width={150} height={150} alt="Dogecoin Logo" />
      <h1 className="title">Live Dogecoin Price</h1>
      <h5 className="subtitle">Dogecoin To The Moon 🚀🌕</h5>
      <div className="prices-container">
        <PriceCard type="low" price={ticker.low} />
        <PriceCard type="high" price={ticker.high} />
        <PriceCard type="current" price={ticker.last} />
      </div>
      <p>
        Dogecoin price updated every 10 seconds seconds from{' '}
        <a href="https://wazirx.com/">WazirX API</a>
      </p>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

We import the useState and useEffect hooks from react library as named exports and axios from the axios package as a default export. The useState hooks takes in the initial value which we have set to an object having values of 0 for high, low and last. It returns us a variable which holds the current state and a function to set the new state. In our case, these are the ticker and setTicker respectively.

Inside the useEffect hook, we define an asynchronous function (since API calls are asynchronous in nature) named as getDogecoinPrice in which we make a request to our API endpoint using axios. We destructure the data from the response and set the state of ticker to data.ticker since we need only the ticker data from response. After the function definition, we call this function once followed by a setInterval with a delay of 10000ms (10 seconds) which will run our function and call our API every 10 seconds to get the updated price.

The useEffect hooks also take an array of dependencies as a second argument but since we need to run the setInterval only once, when the component is mounted, we can keep it as an empty array.

The price attribute of PriceCard component can be set to ticker.low, ticker.high and ticker.last respectively to get the lowest, highest and last traded value. Since ticker is a state variable, React will automatically re-render the UI every time its value changes.

Finally, here's what we have built:

Final Output


Congratulations! You have built yourself a nice and simple web application using React to stay updated with Dogecoin. If you faced any difficulties during building it, please have a look at the GitHub repo or post a comment down below and I'll be more than happy to help you out. That's all, folks!

Top comments (13)

Collapse
 
codebyjustin profile image
Justin

To the moon !

Collapse
 
itsnitinr profile image
Nitin Ranganath

🚀🌕

Collapse
 
rafavls profile image
Rafael

Awesome project!
I'd suggest updating the README.md file in your repo to make it more personal. Other than that, great post!

Collapse
 
itsnitinr profile image
Nitin Ranganath

Definitely, I'll do that right away.

Collapse
 
andrewbaisden profile image
Andrew Baisden

Dogecoin has really grown in popularity thanks to Elon Musk.

Collapse
 
bc profile image
Brian Canzanella

fun and informative!

Collapse
 
commentme profile image
Unnati Bamania

Beginners must try! One of the coolest and unique project for ones who've started learning react.

Collapse
 
p77u4n profile image
Pham Tran Tuan • Edited

You should clear the setTimeout side effect in your useEffect hook :))). However, thanks for your post

Collapse
 
itsnitinr profile image
Nitin Ranganath

Fixed. Thanks a lot for notifying!

Collapse
 
tyry327 profile image
Tyler Reicks

Cool tutorial! Unfortunately the Heroku app is down so the ticker doesn't work :(

Collapse
 
itsnitinr profile image
Nitin Ranganath

Ahh, that sucks. I've must've exceeded my free quota :(

Collapse
 
olaoyevick profile image
Victor Olaoye

Fantastic stuff 🙌

Collapse
 
olaoyevick profile image
Victor Olaoye

Fantastic stuff 🙌