Crypto Tracker 4.12 _ Price Chart part Two

Eugenius1st·2022년 4월 8일
0

ReactJS_MasterClass

목록 보기
28/48

API에서 받아온 data 시각화 하기

APEXCHART 사용

APEXCHAR란 자바스크립트 chart library 이다.

다양한 차트가 있다.

사용하기 위해선 명령어를 실행시켜야 한다.

intergrations 에서 react 꺼로 들어가서 npm install 한다.

npm install --save react-apexcharts apexcharts

그리고 그 전에 typescript에게 data가 어떻게 생겼는지 말을 해줘야 한다.

API가 준 값을 알려주자.
인터페이스로 API의 타입을 정의해준다

그리고 apex를 import 한 후 다양한 옵션들을 설정해 주면


이러한 차트가 나타나게 된다.

즉 어떤 옵션이 들어가야하는지만 안다면 원하는 대로 차트를 꾸밀 수 있는 것이다.

이는 사이트의 options 에서 확인할 수 있다.

Chart.tsx

import { useQuery } from 'react-query';
import { fetchCoinHistory } from './api';
import ApexChart from 'react-apexcharts';

interface IHistorycal {
  time_open: string;
  time_close: string;
  open: number;
  high: number;
  low: number;
  close: number;
  volume: number;
  market_cap: number;
}

interface ChartProps {
  coinId: string;
}

function Chart({ coinId }: ChartProps) {
  const { isLoading, data } = useQuery<IHistorycal[]>(['ohlcv', coinId], () =>
    fetchCoinHistory(coinId)
  );
  //14개를 받아와야 하므로 배열로 전달.
  return (
    <div>
      {isLoading ? (
        'Loading chart...'
      ) : (
        <ApexChart
          type="line"
          series={[
            {
              name: 'price',
              data: data?.map((price) => price.close) as number[],

              // 맵함수는 리턴하는 값으로 array를 만들어 준다.
              //as 를 이용하셔도 됩니다. 저 데이터는 number 배열이다! 라고강제함.
              // 맵함수는 리턴하는 값으로 array를 만들어 준다.
            },
          ]}
          //series는 보내고 싶은 모든 data가 들어있다.
          options={{
            theme: { mode: 'dark' },
            chart: {
              width: 500,
              height: 300,
              toolbar: { show: false },
              background: 'transparents',
            },
            grid: { show: false },
            stroke: { curve: 'smooth', width: 3 },
            yaxis: { show: false },
            xaxis: {
              labels: { show: false },
              axisTicks: { show: false },
              axisBorder: { show: false },
            },
          }}
        />
        //apexvhart는 위와같이 다양한 옵션이 있다.
      )}
    </div>
  );
}
// const params = useParams();
// console.log(params);
//coinId 가져오기 또는 서브 Router 에서 porps로 받아오기
export default Chart;

##Coins.tsx

import styled from 'styled-components';
import { Link } from 'react-router-dom';
import { useQuery } from 'react-query';
import { fetchCoins } from './api';
const Container = styled.div`
  padding: 0px 20px;
  max-width: 480px;
  margin: 0 auto;
`;

const Header = styled.header`
  height: 20vh;
  display: flex;
  justify-content: center;
  align-items: center;
`;

const CoinsList = styled.ul``;

const Coin = styled.li`
  background-color: white;
  color: ${(props) => props.theme.bgColor};
  margin-bottom: 10px;
  padding: 20px;
  border-radius: 15px;

  a {
    padding: 5px; // 좀 더 넓은 범위에서 transition 효과 적용 가능
    transition: color 0.2s ease-in;
  }

  &:hover {
    a {
      color: ${(props) => props.theme.accentColor};
    }
    // 아래에서는 a가 아닌 Link라는 이름으로 사용했지만
    // css에서는 anchor 를 선택해야 했다. 이건 모든 react router link들이
    // 결국에는 anchor로 바뀔거기도 하고,
    // react router dom이 우리 대신 설정을 도와줄 특별한 event listener들이 있기도 하다
  }
`;

const Title = styled.h1`
  font-size: 48px;
  color: ${(props) => props.theme.accentColor};
`;

const Loader = styled.span`
  text-align: center;
  display: block;
`;

const Img = styled.img`
  width: 25px;
  height: 25px;
  margin-right: 10px;
`;

interface ICoin {
  id: string;
  name: string;
  symbol: string;
  rank: number;
  is_new: boolean;
  is_active: boolean;
  type: string;
}

function Coins() {
  const { isLoading, data } = useQuery<ICoin[]>('allCoins', fetchCoins);
  console.log(isLoading, data);
  //useQery는 두개의 식별자가 필요하다. 첫번째는 고유식별자, 두번째는 fetcher함수이다.
  // useQuery는 isLoading 이라고 불리는 boolean값을 return하는데 이전에 있던
  // const[lading,setLoading]과 setLoading(false)를 대체할 수 있는 것이다.
  // 총 설명: useQuery hook에서 fetcher함수 fetchCoins를 불러오고 그함수가
  // isLoading 즉, fetcher함수가 끝난다면 react Query가 말해줄 것이다.
  // 그리고 return 값을 data에 넣어줄 것이다. 아래에서 state에 넣었던 것처럼..
  // +) data 타입을 명시하기 위해 <CoinInterface[]>를 넣어준다.

  // 위 코드와 아래 코드는 같다.

  // const [coins, setCoins] = useState<CoinInterface[]>([]);
  // const [loading, setLoading] = useState(true);
  // useEffect(() => {
  //   (async () => {
  //     const response = await fetch('https://api.coinpaprika.com/v1/coins');
  //     const json = await response.json();
  //     setCoins(json.slice(0, 100));
  //     setLoading(false);
  //   })();
  // }, []);

  return (
    <Container>
      <Header>
        <Title>코인</Title>
      </Header>
      {isLoading ? (
        <Loader>"Loading..."</Loader>
      ) : (
        //loading 이 참이면 Loading... 출력, 거짓이면 CoinsList 보여줌
        <CoinsList>
          {data?.slice(0, 100).map((coin) => (
            <Coin key={coin.id}>
              <Img
                src={`https://cryptoicon-api.vercel.app/api/icon/${coin.symbol.toLowerCase()}`}
              />

              <Link
                to={{
                  pathname: `/${coin.id}`,
                  state: { name: coin.name },
                  //Link를 이용해 string 이외에 더 많은 데이터를 보낼 수 있다
                }}
              >
                {coin.id}
              </Link>
            </Coin>
          ))}
        </CoinsList>
      )}
    </Container>
  );
}

export default Coins;

api.ts

const BASE_URL = `https://api.coinpaprika.com/v1`;

export async function fetchCoins() {
  // const response = await fetch(`${BASE_URL}/coins`);
  // const json = await response.json();
  // return json;
  //가독성 높은 오래된 방법
  return fetch(`${BASE_URL}/coins`).then((response) => response.json());
  // 두 코드는 같은 것이다. fetcher 함수인 fetchCoin 은 URL을 부르고 URL로 부터 json을 return 한다.
}

export async function fetchCoinInfo(coinId: string) {
  //coinId 타입 명시 필요, coin Id를 fetch하는 함수
  return fetch(`${BASE_URL}/coins/${coinId}`).then((response) => response.json());
}

export async function fetchCoinTickers(coinId: string) {
  //coinId 타입 명시 필요 coin Ticker를 fetch하는 함수
  return fetch(`${BASE_URL}/tickers/${coinId}`).then((response) => response.json());
}

export function fetchCoinHistory(coinId: string) {
  const endDate = Math.floor(Date.now() / 1000);
  const startDate = endDate - 60 * 60 * 24 * 7 * 2;
  return fetch(
    `${BASE_URL}/coins/${coinId}/ohlcv/historical?start=${startDate}&end=${endDate}`
  ).then((response) => response.json());
}
profile
최강 프론트엔드 개발자가 되고싶은 안유진 입니다

0개의 댓글