Bitcoin Price Fetcher

Create a custom hook to regularly fetch the price of Bitcoin.


Environment

Use the environment you are most comfortable with. I recommend using create-react-app to create a local version of the project so that you can inspect the DOM easily from your browser when debugging. Alternatively, you can work from a blank React template in CodeSandbox. Starter code is provided after the problem specification.

Specification

Write a custom hook called useBitcoin() that returns the value of Bitcoin in US dollars. Every minute, the price should be re-fetched and the returned variable should be updated (this is the same rate at which the API updates the price). To retrieve the price of Bitcoin in US dollars, issue a GET request to the following URL: https://api.coindesk.com/v1/bpi/currentprice.json. The free API returns a JSON of the following form:

{ 
  "time":{
    "updated":"Dec 28, 2023 23:35:00 UTC",
    "updatedISO":"2023-12-28T23:35:00+00:00",
    "updateduk":"Dec 28, 2023 at 23:35 GMT"
  },
  "disclaimer": "This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org",
  "chartName":"Bitcoin",
  "bpi":{
    "USD":
      {"code":"USD",
      "symbol":"$",
      "rate":"42,745.8531",
      "description":"United States Dollar",
      "rate_float":42745.8531
    },
    "GBP":{
      "code":"GBP",
      "symbol":"£",
      "rate":"35,718.0929",
      "description":"British Pound Sterling",
      "rate_float":35718.0929
    },
    "EUR":{
      "code":"EUR",
      "symbol":"€",
      "rate":"41,640.7018",
      "description":"Euro",
      "rate_float":41640.7018
    }
  }
} 

In the solution below, I use the Axios library to issue the GET request, but you should use the data-fetching library that you are most comfortable with. While developing, be careful not to accidentally issue requests to the API in an infinite loop so as not to have later requests blocked. If you are unfamiliar with building custom hooks in React, you can read the documentation here. Finally, render a component that makes use of your custom hook and displays the price on the screen. While the value returned from the hook is undefined, display a loading screen instead.

Starter Code

Here is some code to get you started:


import React, { useEffect, useState } from "react";
import axios from "axios";

const useBitcoin = () => {
  // YOUR CODE HERE
};

function App() {
  // YOUR CODE HERE TOO
}

export default App;

For comparison as you develop, the solution below is roughly 35 lines.

Solution

import React, { useEffect, useState } from "react";
import axios from "axios";

const useBitcoin = () => {
  const [value, setValue] = useState();

  useEffect(() => {
    const fetchValue = async () => {
      try {
        const res = await axios.get(
          "https://api.coindesk.com/v1/bpi/currentprice.json"
        );
        setValue(res.data.bpi.USD.rate_float);
      } catch {
        console.error("Failed to update price");
      }
    };

    fetchValue();

    const interval = setInterval(() => fetchValue(), 60000);
    return () => clearInterval(interval);
  }, []);

  return value;
};

function App() {
  const value = useBitcoin();

  return (
    <div style={{ display: "flex", justifyContent: "center" }}>
      {value ? (
        <h1>{"Bitcoin Price: $" + value + " USD"}</h1>
      ) : (
        <h4>Fetching price...</h4>
      )}
    </div>
  );
}

export default App;

The useBitcoin() custom hook wraps two built-in React hooks, useState() and useEffect(), and returns the variable initialized with useState(). The callback function passed to useEffect() defines an asynchronous function to fetch the current bitcoin price and set the state variable to that price. That asynchronous function is then called (so that the price is fetched when the component first mounts) and sets up an interval to recall the async function every minute. We also include an empty dependency array as the second argument to the useEffect() function; without it, the function passed via useEffect()’s first argument would render on every render. Because the function we use updates state, this would create an infinite loop. Finally, we use a ternary operator to conditionally render the loading screen or the fetched price.


hook
useEffect
useState
axios