Skip to content
Eyup Ucmaz
TwitterGithubLinkedinMail Me

Project Diary Crypto Coin Stats

Projects Diary, Crypto Coin2 min read

coin

hey there 👋🏻 today we’re gonna talk about my last project and I’ll try to describe what i have done.

What did i would like to build?

I wanted to build something i will use API's and showing data with fancy way 🙂 As you know there is hype about crypto currencies. So i decided to make a Crypto Coin Status App. That thought was beginning of my learning something new. So lets dive in 👇

"Create-React-App"

I use the react framework in this project which is i still learning about it. I created a new project. After some cleaning the files. I searched APIs to implement to project. Then i found the CoinStats, they have a public API. And it has a data what i want to show in project.

Exploring the API

Let's look into the API data. What we can got it. Base Url is look like this 👉 https://api.cointats.app/public/v1/coins It's return a JSON object of coins and details about them.

{
"coins": [
{
"id": "bitcoin",
"icon": "https://static.coinstats.app/coins/Bitcoin6l39t.png",
"name": "Bitcoin",
"symbol": "BTC",
"rank": 1,
"price": 35547.10913935076,
"priceBtc": 1,
"volume": 37572848407.127914,
"marketCap": 673182692669.0496,
"availableSupply": 18937762,
"totalSupply": 21000000,
"priceChange1h": -0.86,
"priceChange1d": 0.01,
"priceChange1w": -17.48,
"websiteUrl": "http://www.bitcoin.org",
"twitterUrl": "https://twitter.com/bitcoin",
"exp": [
"https://blockchair.com/bitcoin/",
"https://btc.com/",
"https://btc.tokenview.com/"
]
},
{
"id": "ethereum",
"icon": "https://static.coinstats.app/coins/EthereumOCjgD.png",
"name": "Ethereum",
"symbol": "ETH",
"rank": 2,
"price": 2459.1259869574947,
"priceBtc": 0.06922216713258655,
"volume": 38181447762.57734,
"marketCap": 293322848926.86,
"availableSupply": 119279309.1865,
"totalSupply": 0,
"priceChange1h": -1.53,
"priceChange1d": -0.27,
"priceChange1w": -26.04,
"websiteUrl": "https://www.ethereum.org/",
"twitterUrl": "https://twitter.com/ethereum",
"contractAddress": "0x2170ed0880ac9a755fd29b2688956bd959f933f8",
"decimals": 18,
"exp": [
"https://etherscan.io/",
"https://ethplorer.io/",
"https://blockchair.com/ethereum",
"https://eth.tokenview.com/",
"https://moonriver.moonscan.io/token/0x639a647fbe20b6c8ac19e48e2de44ea792c62c5c"
]
}
]
}

API is also takes a few parameters.

  • skip takes the number of which amount of you want to skip.
  • limit takes the number of how many coin data you want.
  • currency it takes the currency of coin prizes (USD,EUR,TRY)

As you can see each coin data have a bunch of detail data. So i’ll use icon, name, price, symbol, priceChange1d, marketCap and websiteUrl data to show on my project.

Creating the Components

In this case i have two components. Maybe i should have separated them. 🤔 anyway first one is Header second one is Coin. Header would have a search bar, Github link, option element(for change currency) and the title.

src/components/Header.js
1import { useContext } from "react";
2import { CoinContext } from "../../Context/CoinContext";
3import styles from "./Header.module.css";
4import { VscGithubAlt } from "react-icons/vsc";
5
6const Header = () => {
7 // I'm using useContext hook to get states and setstates functions
8 // searchInput is a state of search bar and it sets with setSearchInput
9 // I've also changing currency of data options so in this reason i should
10 // keep in a state which currency showing.
11 const { searchInput, setSearchInput, setCurrency } = useContext(CoinContext);
12
13 // with this function setting the searchInput state
14 const handleChange = (event) => {
15 setSearchInput(event.target.value);
16 };
17
18 return (
19 <>
20 <main className={styles.container}>
21 <nav>
22 {/* CURRENCY OPTIONS */}
23 <select
24 className={styles.currency}
25 name="currency"
26 {/* setting the currency with this arrow function */}
27 onChange={(e) => setCurrency(e.target.value)}
28 >
29 <option value="USD">USD</option>
30 <option value="EUR">EUR</option>
31 <option value="TRY">TRY</option>
32 <option value="GBP">GBP</option>
33 </select>
34 {/* LINKS */}
35 <a
36 href="https://github.com/eyupucmaz/crypto-app"
37 className={styles.github}
38 target="_blank"
39 rel="noopener noreferrer"
40 >
41 <VscGithubAlt />
42 </a>
43 </nav>
44
45 {/* SEARCH BAR AND HEADER */}
46 <h1 className={styles.container__title}> Crypto Coin Stats</h1>
47 <div className={styles.search}>
48 <input
49 type="text"
50 name="currency"
51 className={styles.search__input}
52 value={searchInput}
53 onChange={handleChange}
54 placeholder="Search for Coins"
55 />
56 </div>
57 </main>
58 </>
59 );
60};
61
62export default Header;

i explained most of part in gist file. i also used the module css to styling all things but i’m not gonna dive in. So header components should looks like this 👇

header component
src/components/Coin.js
1import styles from "./Coin.module.css"; // using module css for styling
2import { AiFillCaretDown, AiFillCaretUp } from "react-icons/ai"; // icons for show increase and decrease
3import { useContext } from "react"; // hook for getting state of currency
4import { CoinContext } from "../../Context/CoinContext"; // context
5
6// Components take a data prop which is an object of each coin data
7const Coin = ({ data }) => {
8 // getting currency state with context hook
9 const { currency } = useContext(CoinContext);
10
11 return (
12 <>
13 <div className={styles.container}>
14 <div className={styles.card}>
15 <div className={styles.card__top}>
16 // Showing icon of coin, and getting a name of coin for alt attribute
17 <img
18 className={styles.icon}
19 src={data.icon}
20 alt={`Icon of ${data.name}`}
21 />
22 <div className={styles.coin__info}>
23 // showing name of coin
24 <p className={styles.coin__name}>{data.name}</p>
25 <p className={styles.coin__price}>
26 // in this case looking for price of coin // if its less than 1,
27 showing 8 digits of number after 0(zero) // if its not, showing
28 data 3 digits
29 <strong>
30 {data.price < 1
31 ? data.price.toFixed(8)
32 : data.price.toFixed(3)}
33 </strong>
34 // this is where i using currency state (BTC/USD)
35 <span className={styles.coin__price__currency}>
36 {` ${data.symbol}/${currency}`}
37 </span>
38 </p>
39 <p className={styles.coin__changes}>
40 // I also showing a daily changes of currency // in reason i
41 checking the currency changes is under 0 or not // if under the
42 zero showing red down arrow if is not showing green arrow
43 {data.priceChange1d < 0 ? (
44 <span className={styles.price_down}>
45 <AiFillCaretDown />
46 {data.priceChange1d}
47 </span>
48 ) : (
49 <span className={styles.price_up}>
50 <AiFillCaretUp />
51 {data.priceChange1d}
52 </span>
53 )}
54 </p>
55 </div>
56 </div>
57 <div className={styles.card__bottom}>
58 <p className={styles.coin__market}>
59 // Showing market cap of coin
60 <span className={styles.coin__market__text}>Market Cap: </span>
61 // also using currency state to show how much is it
62 {`${data.marketCap} ${currency}`}{" "}
63 </p>
64 // there is where you can visit website of coin
65 <a
66 target="_blank"
67 rel="noopener noreferrer"
68 href={data.websiteUrl}
69 className={styles.coin__website}
70 >
71 Official Web Site
72 </a>
73 </div>
74 </div>
75 </div>
76 </>
77 );
78};
79
80export default Coin;

So component is looks too much maybe i should have separated few elements as a different components on it. I’ll think about it. So with styling it should looks like this 👇

Coin Component

Creating a Context

I figure out to something while writing this blog. I created a context as a separate file but i declared values in App.js file. I’ll fix them later. So my CoinContext.js file is looks like this 👇

1import { createContext } from 'react';
2export const CoinContext = createContext({});

I know its silly 😅 but I’ll definitely refactor all project ASAP. So let’s take look to App.js file.

Getting Data From API and Provide to Components

Here we are! 🙂 We almost done with the project. First all of i would like to describe states of app.

1const [searchInput, setSearchInput] = useState(“”);

First one is state of input value which is we used in header component. Reason why i did not declared in header component. I’ll use in a function for filter the data. I’m getting data in App.js file. So this is why.

1const [coinData, setCoinData] = useState([]);

This state as you can see where i collect the data of coins. I’ll pass this state to Coin component after getting data.

1const [currency, setCurrency] = useState(USD);

Remember we have options for currency in Header component. API takes parameters currency is a one of them. So default is a “USD”. It’s gonna Call API when you change the currency every time. Because I pass the currency state to useEffect Hook.

1const [error, setError] = useState(null);

This is where i collect the error. If there is an error while calling API. It will shown in below the Header component.

1const [loading, setLoading] = useState(true);

And the final one is loading state. I’m using this state for while data getting from API. Rendering a loading icon to showing getting data. It will be looks like this 👇

loading
src/App.js
1import { useState, useEffect } from "react";
2import styles from "./App.module.css";
3import Coin from "./components/Coin/Coin";
4import Header from "./components/Header/Header";
5import { CoinContext } from "./Context/CoinContext";
6import { VscLoading } from "react-icons/vsc";
7// I using AXIOS to call api
8// It makes easier getting data from api.
9// You won't be worry about parsing JSON
10import axios from "axios";
11
12// I declared the API url like this,
13// currency is empty we will use currency state for that.
14const API_URL =
15 "https://api.coinstats.app/public/v1/coins?skip=0&limit=1000&currency=";
16function App() {
17 // All our states
18 const [searchInput, setSearchInput] = useState("");
19 const [coinData, setCoinData] = useState([]);
20 const [currency, setCurrency] = useState("USD");
21 const [error, setError] = useState(null);
22 // Default value of loading is true
23 const [loading, setLoading] = useState(true);
24
25 // There is where app calling API
26 // I pass the currency state as a dependency for hook
27 // It will call API every changes of currency state
28
29 useEffect(() => {
30 axios
31 .get(`${API_URL}${currency}`)
32 .then((res) => {
33 setCoinData(res.data.coins);
34 })
35 .catch((err) => {
36 setError(err.message);
37 })
38 .finally(() => {
39 // After finished the getting data it set the loading to false
40 setLoading(false);
41 });
42 }, [currency]);
43
44 // I used a variable for the collect a filtering data
45 // filter function returns a new array
46 // It's filtering by coin names
47 const filteredList = coinData.filter((coin) => {
48 return coin.name.toLowerCase().includes(searchInput.toLowerCase());
49 });
50
51 return (
52 <div className={styles.container}>
53 {/* Wrapped all components by Coin Context provider */}
54 <CoinContext.Provider
55 {/* Provider takes value attribute to provide to child components
56 in this case i'm using coinData, currency and set methods.
57 */}
58 value={{ searchInput, setSearchInput, coinData, setCurrency, currency }}
59 >
60 <Header />
61 {/* Showing Error */}
62 {error && `${error}`}
63 {/* Showing Loading ICON */}
64 {loading && (
65 <span className={styles.loading}>
66 <VscLoading />
67 </span>
68 )}
69 {/* There is where shown coin data. I'm using filteredList of coins.
70 It will show all coins when inputSearch state is empty. But when you
71 typed a letter it wont call api again it will use data which is already
72 getting from API.
73 */}
74 <section className={styles.coins}>
75 {filteredList.map((coin) => {
76 // Passing a rank as a key value & passing a data
77 return <Coin key={coin.rank} data={coin} />;
78 })}
79 </section>
80 </CoinContext.Provider>
81 </div>
82 );
83}
84
85export default App;

Conclusion

I definitely learn more than coding while writing this blog. I saw my mistakes and thought how i should improve my coding skills. I also learned about Context API to “why we should use”, “when we should use”. Also how we should’t use 😅 Hopefully that blog helps you to figure out something. Because it helped me. 🙂

Resources: