Project Diary Crypto Coin Stats
— Projects Diary, Crypto Coin — 2 min read
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.
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 functions8 // searchInput is a state of search bar and it sets with setSearchInput9 // I've also changing currency of data options so in this reason i should10 // keep in a state which currency showing.11 const { searchInput, setSearchInput, setCurrency } = useContext(CoinContext);12
13 // with this function setting the searchInput state14 const handleChange = (event) => {15 setSearchInput(event.target.value);16 };17
18 return (19 <>20 <main className={styles.container}>21 <nav>22 {/* CURRENCY OPTIONS */}23 <select24 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 <a36 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 <input49 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 👇
1import styles from "./Coin.module.css"; // using module css for styling2import { AiFillCaretDown, AiFillCaretUp } from "react-icons/ai"; // icons for show increase and decrease3import { useContext } from "react"; // hook for getting state of currency4import { CoinContext } from "../../Context/CoinContext"; // context5
6// Components take a data prop which is an object of each coin data7const Coin = ({ data }) => {8 // getting currency state with context hook9 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 attribute17 <img18 className={styles.icon}19 src={data.icon}20 alt={`Icon of ${data.name}`}21 />22 <div className={styles.coin__info}>23 // showing name of coin24 <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, showing28 data 3 digits29 <strong>30 {data.price < 131 ? 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 i41 checking the currency changes is under 0 or not // if under the42 zero showing red down arrow if is not showing green arrow43 {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 coin60 <span className={styles.coin__market__text}>Market Cap: </span>61 // also using currency state to show how much is it62 {`${data.marketCap} ${currency}`}{" "}63 </p>64 // there is where you can visit website of coin65 <a66 target="_blank"67 rel="noopener noreferrer"68 href={data.websiteUrl}69 className={styles.coin__website}70 >71 Official Web Site72 </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 👇
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 👇
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 api8// It makes easier getting data from api.9// You won't be worry about parsing JSON10import 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¤cy=";16function App() {17 // All our states18 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 true23 const [loading, setLoading] = useState(true);24
25 // There is where app calling API26 // I pass the currency state as a dependency for hook27 // It will call API every changes of currency state28
29 useEffect(() => {30 axios31 .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 false40 setLoading(false);41 });42 }, [currency]);43
44 // I used a variable for the collect a filtering data45 // filter function returns a new array46 // It's filtering by coin names47 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.Provider55 {/* Provider takes value attribute to provide to child components56 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 you71 typed a letter it wont call api again it will use data which is already72 getting from API.73 */}74 <section className={styles.coins}>75 {filteredList.map((coin) => {76 // Passing a rank as a key value & passing a data77 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. 🙂