크립토 트래커(차트)

김현준·2024년 3월 3일
0

#5.0 Setup

모든 것을 한꺼번에 연습하기 위해 코인 트래킹 어플리케이션을 만들어보자.
coinpaprika라는 API가 있다.
코인 정보, 가격, 과거 가격 등등 많은 것을 보여준다.
만들고 데이터를 패칭하는 방법도 알아보자. 그 후에 리액트 쿼리로 방식을 바꿀 것이다.

  • 리액트 쿼리:
    훨씬 좋고 편리한 방식으로 데이터를 fetch시킬 수 있다.

리액트 쿼리를 사용하기 전에 직접 패치해보자.

npm i react-router-dom@5.3.4 react-query를 설치하자.

그리고 계획은
/ -> 모든 코인
/:id -> 선택한 코인 상세정보

중첩된 라우터(한 스크린 내에 또다른 라우터)
/btc/information
/btc/chart

그리고 src폴더에 routes폴더를 만들자.
그리고 그 안에 Coin.tsx스크린과 Coins.tsx스크린과을 만들자.

src폴더에 Router.tsx도 만들자.
그리고 Router.tsx에서 리액트 돔이 타입이 없다고 하는데
npm i —save-dev @types/react-router-dom@5.3 설치하면 된다.

  • Switch: 한 번에 하나의 라우터를 렌더링할 수 있는 방법


Router.tsx에 라우터를 만들고,

<Route path="/:coinId">
이제 이 부분을 잡아주자.

useParams() 훅으로 id를 잡아줄 수 있다.

최종적으로 이렇게 해주면 된다.

const {coinId }=useParams<{coinId:string}>();도 가능

#5.1 Styles

CSS 셋업과 Theme 셋업을 해보자.
CSS 셋업은 두 가지 방법이 있다.

하지만 다른 방법으로 해보자.
https://github.com/zacanger/styled-reset/blob/master/src/index.ts
위 사이트에서 리셋css를 긁어와서

globalStyle에 넣어주었다.

폰트도 바꾸자.
https://fonts.google.com에서 마음에 드는 것을 선택 후 import를 긁어서

globalStyle 가장 위에 넣어준다.
그리고 링크의 밑줄을 없애고, 모든게 box-sizing: border-box옵션을 갖도록 했다.

그리고 테마를 만들어보자.
Flat UI Color
https://flatuicolors.com/palette/gb 이 사이트에서

테마 색깔도 바꿔주고 타입도 지정해줬다.

<ThemeProvider theme={theme}>
      <App />
    </ThemeProvider>

그리고 위처럼 App은 ThemeProvider 내에 존재하기에 App에서 Theme에 접근할 수 있다.

그래서 위처럼 GlobalStyle에서 접근할 수 있다는 것이다. 그럼 다크모드가 완성된다.

그리고 coins에 accentColor도 지정해줬다.
다 됐다. 이제 코딩을 할 건데 모바일 버전도 할 것이다.

#5.2 Home part One(홈 파트 1)

coins 스크린의 스타일을 바꾸자.
일단 여기선 컴포넌트 없이 프로토타입을 하는 것이 얼마나 멋진지만 알아보자.

Coins 스크린에 기본 골자는 이렇다.
우선 이렇게 기본 골자를 만들고, 코인의 데이터 목록이 잘 뜨는지 확인한 다음, 꾸며보자.

#5.3 Home part Two

API로부터 데이터를 fetch(가져오기)해보자.
일단 데이터들의 인터페이스를 만들어줘야 한다.

#5.4 Route States

https://coinicons-api.vercel.app/
위 사이트에서 암호화페의 로고를 가져올 수 있다.

위의 주소를 누르면 아이콘이 나오는데 뒤에다 코인의 이름을 쓰기만 하면 된다.


코인 이름 앞에다가 이미지를 넣어주었다. 심볼이 대문자이므로 소문자로 변환했다.

다른 페이지에서 다시 올 때마다 새로 로딩되는 문제는 나중에 해결하자.
https://api.coinpaprika.com/#section/Rate-limit
코인파프리카 API에서 많은 것들을 받아올 수 있다.

이제 Coins에서 Coin으로 넘어갈 건데, Coin으로 넘어갈 때 또 로딩을 보는 것은 좋은 UI가 아니다.
그러므로 우리가 보이지 않는 방식으로(비하인드더씬) 데이터를 보내는 방법을 알아보자.

화면을 이동할 때 데이터를 보낸다는 것은 파라미터를 이용해 URL에게 코인의 정보를 넘기는 것이다. 이런 방식으로 한 화면에서 다른 화면으로 정보를 받아올 수도 있다.
바로 URL을 쓰지 않고, State를 사용하는 것이다.

리액트에서 링크 컴포넌트를 사용할 때 두 가지 옵션이 있다.

  • 첫 번째:

    <Link to={`/${coin.id}`}>

    지금 하던 것처럼 string을 이용하는 것.

  • 두 번째:

    오브젝트로 데이터를 보낼 수도 있다.

string 하나만 보내는 것 대신 두 번째 방법으로 비하인드더씬 데이터를 보내보자.

이렇게 하면 유저는 화면 전환 시 로딩을 볼 필요가 없어진다.
이제 coin 스크린에서 state를 받아보자.

코인 coin.name로 보내는게 좀 못 생겼다. 간단하게 해결하자.
리액트 라우터가 보내주는 로케이션 오브젝트에 접근하기만 하면 된다.

이제 이미 가진 데이터를 사용하므로 API가 줄 때까지 기다릴 필요 없다.
state는 우리가 Coins화면을 열 때와, Coin화면으로 넘어갈 때 생성된다.

에러
하지만 시크릿 창으로 Coin페이지를 열면 에러가 난다. state가 정의되지 않았다고 하는데
state가 생성되려면 Home화면인 Coins를 먼저 열어야 하기 때문이다.

위와 같이 해결했다. 나중에 로딩 문구대신 홈 화면으로 가라고 해도 될 듯

useLocation과 useParams의 차이:
useLocation은 이정 페이지 자체에서 일부 정보를 가져오는 것이고,
useParams은 이전 페이지에서 특성 정보의 id 등을 받아 API로 호출하는 것

#5.5 Coin Data

Coin 스크린에 상세 데이터를 출력해보자.
coin id로 코인 받기 (Coins)
https://api.coinpaprika.com/v1/coins/btc-bitcoin
https://api.coinpaprika.com/#operation/getCoinById

coin id로 특정 코인에 대한 시세 정보 얻기 (Tickers)
https://api.coinpaprika.com/v1/tickers/btc-bitcoin
https://api.coinpaprika.com/#operation/getTickersById

URL에 coinId를 넣어야 하는데 이건 이미 우리 앱이 갖고 있다.



두 개의 api를 불러오고 화면에 info.id를 출력해보려 했지만 빈 오브젝트라고 생각한다.
ts를 사용할 때 이럴 때마다 ts에게 일일이 설명해줘야한다는 것이 짜증난다.
다행히 이런 것들은 자동으로 생성되기 할 수도 있다.
API의 type에 대한 정보를 자동생성할 수 있다.

#5.6 Data Types

ts에게 데이터에 대해 설명해주자.
ts가 info와 proceInfo를 그저 빈 오브젝트로 알고있기 때문이다.

콘솔에 뜨는 것을 우클릭하고 저것을 누르면 temp1에 저장된다. 둘 다 해주자.

이렇게 temp1의 키값만 조회할 수 있다.
join()은 배열의 모든 요소를 연결해 하나의 문자열로 만든다.

그리고 인터페이스에 붙여넣고 모든 쉼표들을 컨트롤+D로 선택한 다음 삭제하고 엔터를 누른다.

그러면 모든 킷값들이 정렬이 된다.
그리고 모든 키들을 드래그 하고 Shift+Alt(Option)+i:(가장 우측 끝으로 포커싱)

그리고 value값을 조회하고 map으로 값들의 타입을 조회했다.
그것을 join으로 문자열로 만들었다.

그리고 아까처럼 쉼표를 없애고 엔터를 눌러 세로정렬한 후,
키에서 Shift+Alt(Option)+i눌러 문자열의 끝을 선택한 후 값들을 복붙했다.
하지만 tags랑 team은 실제로 오브젝트가 아니다. temp1을 보면 오브젝트로 이뤄진 배열임

무엇으로 이루어졌든 배열이 있기만 하면, 그게 뭔지 직접 설명해줘야 한다.
일단 나한텐 필요없는 부분이니 오브젝트는 다 지우자.


이제 info데이터에 넣고 쓸 수 있다.

#5.7 Nested Routes part One

이제 스크린을 paint해보자. 이건 알아서 했다.
그리고 리액트 라우터에 있는 nested router를 사용할 것이다.

  • nested router:
    라우터 안에 있는 또 다른 라우터. 웹사이트에서 탭을 사용할 때 매우 유용

예를 들면 한 화면에 차트와 그래픽이라는 두 개의 탭이 필요하다고 치자.
그 탭들을 State에서 컨트롤하는 것 대신에 url에서 컨트롤하고 싶다.
url로 하는게 사용자의 사용성이 더 높기 때문이다.
url에 /chart를 이 화면으로 와서 차트가 선택되고, /price를 치면 값이 선택된다.

Chart와 Price 라우터를 만들고, Coin스크린에 switch로 집어넣었다.
이제 url에 /Chart를 입력하면 차트가 뜨고, /Price를 입력하면 Price가 뜬다.

#5.8 Nested Routes part Two

price와 chart를 스위치하는 탭을 만들어보자.

useParams는 URL에서 변수의 정보를 가져다 준다.
링크의 변화 없이 State만으로도 구현할 수 있었겠지만, 링크를 사용해서 URL을 바꿈으로써 트리거가 돼서 리렌더할 수 있는 점은 멋지다.

위처럼 차트와 프라이스를 클릭하면 아래의 부분이 바뀌는 것이다.

위처럼 하고 스타일을 주었다.

  • useRouteMatch:
    사용자가 어떤 URL에 있는지의 여부를 알려준다.
    const priceMatch =useRouteMatch(`/${coinId}/price`);
    만약 위의 URL에 있다면 priceMatch는 그것을 알려줄 것이다.

    콘솔로그하고 price버튼을 누르면 isExact가 true가 된다.(Chart를 선택하면 null이 뜬다)
    이것을 사용해보자.

const Tab =styled.span<{isActive:boolean}>
Tab에 isActive라는 props를 추가하고 불리언 값을 주었다.
그리고 isActive를 priceMatch나 chartMatch에서 받아올 것이다.

다 했지만 스타일을 적용하지 않아 티가 안 날 것이다. 스타일을 적용하자.


해당 탭을 클릭해서 isActive가 ture가 되면 accentColor를, 아닌 경우엔 그냥 기본 컬러를 반환한다.

#5.9 React Query part One

리액트 쿼리에 대해 알아보자.
일단 npm install react query로 설치를 해야한다.

https://tanstack.com/query/v4/docs/react/overview
위 사이트는 공식문서인데 기본적인 형태의 리액트 쿼리를 볼 수 있다.

index.tsx에 리액트 쿼리 설치를 했다.
설치는 이걸로 끝이니 이제 어떻게 사용하는지 알아보자.

리액트 쿼리:
로직들을 축약해줌

예를 들면 coins 스크린에서 데이터를 위한, 로딩을 위한 State를 만들고,
useEffect로 api를 처리하고, 그것을 State에 넣고, 로딩을 false로 두었다.
리액트 쿼리는 이 과정을 자동으로 해준다.

사용하기 위해선 먼저 fetcher 함수를 만들어야 한다.
위의 const res와 const json이 fetcher 함수다.
니코는 기본적으로 API와 관련된 것들은 컴포넌트들과 멀리 떨어지도록 한다.
컴포넌트들이 패치를 하지 않았으면 하기 때문이다.

fetcher 함수는 꼭 fetch promise를 리턴해줘야 한다.(async/await로 처리해도 됨)

src폴더에 새로 만든 api.ts 파일에 패치함수를 넣고(코드가 길어서 promise 형태로 바꿔봄)


주석처리된 코드와 위 코드는 같다.

loading을 isLoading으로 바꿔주고 data에 “'data'은(는) 'undefined'일 수 있습니다.”라는 에러가 뜬다. data 옆에 ?와 slice(0, 100)를 붙여주자.

그리고 특이사항이 화면을 옮길 때 더 이상 로딩이 보이지 않는데 리액트 쿼리가 캐시에 데이터를 저장해두기 때문이다!

#5.10 React Query part Two

현재 목록->코인으로 갈 때는 로딩이 발생하고, 코인->목록으로 갈 때는 발생하지 않는다.
coin스크린의 패칭과 coins스크린의 패칭이 다르기 때문이다.
현재 coins스크린에선 리액트 쿼리를 쓰고 있다.(캐싱이 된다는 것)

캐싱이 된다는 건 리액트 쿼리의 장점 중 하나다.
캐시를 직접 시행하는 건 꽤 어렵지만 리액트 쿼리에 저장한다면 간단하다.

좀 더 시각화하기 위해 리액트 쿼리는 Devtools(개발자도구)라는 것을 갖고 있다.
이것은 렌더할 수 있는 컴포넌트고, 리액트 쿼리에 있는 devtools를 import 해오면 유저의 캐시에 있는 쿼리를 볼 수 있다.
npm i –D @tanstack/react-query-devtools
https://tanstack.com/query/v4/docs/react/devtools

import { ReactQueryDevtools } from "react-query/devtools";

링크에 적힌 것 말고 위처럼 import해야 한다.
그리고 위의 링크를 보고 App에 작성한다.(import만 다른 걸로)

그럼 웹사이트에 Devtools가 생긴다.

useQuery에서 설정한 고유한 키는 개발자도구에 나타난다.


Coin스크린도 바꿔줬다. 그러므로 이제 로딩이 발생하지 않는다.

#5.11 Recap

리액트 쿼리가 쩌는 점

  • fetch함수를 만들 수 있게 해준다. 강력한 캐싱 기능도 있다. 만약 쿼리의 고유한 key값을 리액트쿼리에 넘겨줬다면 리액트쿼리는 유저에게 Loading을 다시 보여주지 않는다.
    key는 고유한 값을 가져야한다. 즉, 2개의 api를 불러오는데 key값이 같으면 안 되므로
  • 첫 번째 키가 카테고리의 역할
  • 두 번째 키가 URL에 잇는 coinId가 되어서 고유한 부분이 되도록 했다.
    const loading =infoLoading ||tickersLoading;

리액트쿼리는 ReactQueryDevtools(App에 설치했음)라는 걸 갖고 있는데 캐시에 어떤 쿼리가 있는지 보여주고, 결과가 무엇인지 보여주고, DataExplorer도 보여준다.

#5.12 Price Chart

세부사항에 차트를 넣어보자.
첫 번째로 차트 컴포넌트는 유저가 보고자 하는 가격의 암호화폐가 무엇인지 알아야 한다.
코인의 가격을 차트에 보여주자.
useQuery를 사용하여 불러오자.


api.tsx에 api를 가져오는 함수를 만들고

Chart.tsx에서 useQuery로 그것을 가져왔다.
다음 시간엔 가져온 데이터를 차트로 나타내는 쉬운 방법을 알아보자.

#5.13 Price Chart part Two

API에서 받아온 data를 시각화 해보자.
APEXCHARTS로 나타낼 것이다.

APEXCHARTS: https://apexcharts.com/
자바스크립트 차트 라이브러리. JS, 앵귤러, 뷰, 리액트와 통합하고 있어서 많은 차트를 갖고 있다.
npm install --save react-apexcharts apexcharts
https://apexcharts.com/docs/react-charts/
리액트 차트의 개요다.
options(Reference)탭에서 많은 것을 설정 가능

import ApexChart from "react-apexcharts";


series: 차트에 표시하려는 데이터
options: 차트의 모든 선택적 구성이 이 속성에 들어간다.

#5.14 Price Chart part Three

price 차트를 좀 더 이쁘게 만들어보자.
fill 프로퍼티는 선에 그라데이션을 적용할 수 있는 옵션이 있다.

에이펙스 차트는 옵션들을 다 찾는게 쉽지 않아서 어렵다고 생각할 수 있다.

그럴 땐 데몬에서 이미 만들어 진 것들을 찾아쓰면 된다.

#5.15 Final Touches

스크린을 실시간처럼 보이게 만들어보자.

오픈 소스를 코인의 가격을 보여주는 것으로 바꿀 것이다.

이름을 Price로 바꾸고 값을 가져와 소수점 2자리까지 보여줬다.

useQuery 훅의 3번째 인자를 쓸 수 있는 방법도 알아보자.

{}안에 3초마다 값을 갱신하게 했다.

그러므로 3초마다 반짝인다.


그리고 이것을 바꾸기 위해 리액트 헬멧이란 것도 사용하자.

npm i react-helmet
재사용 가능한 React 컴포넌트가 문서 헤드에 대한 모든 변경 사항을 관리합니다.
컴포넌트인데 여기서 무엇을 render하던 그게 문서의 헤드로 간다.

profile
기록하자

0개의 댓글

관련 채용 정보