본문 바로가기
FrontEnd/React

[ReactJS] Practice Coin Tracker & Coin Converter - ReactJS 로 영화 웹 서비스 만들기 (8)

by 풍파 2021. 12. 7.

 

이번 시간에는 저번에 이어서 두 번째 실습인 Coin Tracker 를 만들어 볼 것이다.

저번에 useState 실습을 해봤다면 이번엔 useEffect 실습이 될 것이다.

 

 


 

 

#7.2 Practice Coin Tracker

 

데이터 업로드 전 로딩 기능을 추가하고

로딩이 완료되면 코인 리스트를 쭉 보여줄 것이다.

 

코인 리스트는

https://api.coinpaprika.com/v1/tickers

api 이용

 

총 6021개의 코인 리스트

 

 

loading, coins 생성

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

 

loading : 로딩 상태 여부

coins : 코인 리스트

 

 

useEffect 로 데이터 fetch

useEffect(() => {
    fetch("https://api.coinpaprika.com/v1/tickers")
    .then((response) => response.json())
    .then((json) => {
        setCoins(json);
        setLoading(false);
    });
}, []);

 

데이터를 fetch 해서 json 데이터로 받아온 후 coins 에 저장 => setCoins 이용

데이터가 저장되었으니 loading 은 false 로 변경 => setLoading 이용

 

데이터는 첫 render 에 딱 한 번만 가져오면 되므로 [ ]

 

 

화면에 그려지는 부분

return (
    <div>
      <h1>The Coins! {loading ? "" : `(${coins.length})`}</h1>
      {loading ? (
        <strong>Loading...</strong>
      ) : (
        <ul>
        {
          coins.map((coin, index) => 
          <li key={index}>
            {coin.name} ({coin.symbol}) : ${coin.quotes['USD'].price} USD
          </li>)
        }
        </ul>
      )}
    </div>
);

 

h1 > loading 여부에 따라 coins.length 도 출력

 

loading === true > Loading... 출력

 

loading === false > ul 리스트 출력

- map 을 이용해 Bitcoin (BTC) : $51211.208097158 USD 형태로 출력

- map 을 이용하면 element 에게 key 를 줘야한다!!!! 중요

* coin.quotes['USD'].price == coin.quotes.USD.price

 

참고)

map 이용할 때, 괄호 주의

map(() => ( )) 의 형태가 돼야한다.

map(() => { }) 쓰면 적용 X...

 

 

전체 코드

더보기
import { useState, useEffect } from "react";

function CoinTracker() {
  const [loading, setLoading] = useState(true);
  const [coins, setCoins] = useState([]);
  useEffect(() => {
    fetch("https://api.coinpaprika.com/v1/tickers")
    .then((response) => response.json())
    .then((json) => {
      setCoins(json);
      setLoading(false);
    });
  }, []);
  return (
    <div>
      <h1>The Coins! {loading ? "" : `(${coins.length})`}</h1>
      {loading ? (
        <strong>Loading...</strong>
      ) : (
        <ul>
        {
          coins.map((coin, index) => 
          <li key={index}>
            {coin.name} ({coin.symbol}) : ${coin.quotes['USD'].price} USD
          </li>)
        }
        </ul>
      )}
    </div>
  );
}

export default CoinTracker;

 

 


 

 

#7.2.1 Practice Coin Converter - 과제

 

니꼬쌤 말씀대로 Converter 과제를 구현해봤다.

 

USD <-> BTC 처럼 Coin Converter 만들기
select 와 option 이용

 

 

select 로 여러가지 코인들의 선택지가 주어지고

선택한 코인에 따라 다른 Converter 를 보이도록 함

 

 

컴포넌트 분리

우선 선택한 option 에 따라 다른 Converter 컴포넌트를 보여야 하므로

Converter 컴포넌트를 따로 분리했다.

=> CoinConverter & Converter 두 가지로 분리 됨

 

CoinConverter : select 옵션에 따른 <Converter /> 표시

CoinConverter

 

 

Converter : 실제로 Convert 를 수행하는 부분

Converter

 


 

CoinConverter

loading 이나 coins 는 CoinTracker 와 동일하게 구성

 

 

index, selected 추가

const [index, setIndex] = useState("-1");
const [selected, setSelected] = useState([]);

 

index : 어떤 코인을 선택했는지 식별하기 위함

selected : 선택한 코인의 정보를 가진 배열

 

 

화면에 그려지는 부분

return (
  <div>
    <h1>The Coin Converter {loading ? "" : `(${coins.length})`}</h1>
    {loading ? (
      <strong>Loading...</strong>
    ) : (
      <div>
        <select value={index} onChange={onSelect}>
          <option key="-1" value="-1">Select Coin</option>
          {coins.map((coin, idx) => (
            <option key={idx} value={idx}>
              {coin.name}
            </option>
          ))}
        </select>
        <hr />
        {index === "-1" ?
          ("Please Select Coin")
          :
          (<Converter coin={selected} />)
        }
      </div>
    )}
  </div>
);

 

ul & li 부분을 select & option 으로 변경

 

select 값이 변경될 때마다 onSelect 실행

idx 값을 option 의 key 로 이용

- 기본 option 은 "-1" 의 값을 갖는 Select Coin

 

index === "-1" > Please Select Coin 출력

 

index !== "-1" > Converter 출력

- coin 값으로 selected 배열을 넘겨준다.

 

 

onSelect

const onSelect = (event) => {
  setIndex(event.target.value);
  if (event.target.value === "-1"){
    setSelected([]);
  }
  else {
    setSelected(coins[event.target.value]);
  }
}

 

선택한 index 로 변경 => setIndex

 

만약, -1 의 option 을 선택했다면 존재하지 않는 코인이므로 빈 배열로 update

그 외엔 해당 코인의 정보로 update

=> setSelected

 


 

Converter

 

props 받아오기

function Converter({coin}) {  }

 

 

usd, disabled 생성

const [usd, setUSD] = useState(0);
const [disabled, setDisabled] = useState(false);

 

usd : 입력받은 값 저장

disabled : convert 는 한 방향으로 진행되어야 하므로 변환되는 값은 disabled 되도록 함

 

 

화면에 그려지는 부분

return (
  <div>
    <div>
      <label htmlFor="USD">USD </label>
      <input
        id="USD"
        value={
          disabled ? usd * coin.quotes['USD'].price: usd
        }
        type="number"
        onChange={onChange}
        disabled={disabled}
      />
    </div>
    <div>
      <label htmlFor={coin.symbol}>{coin.symbol} </label>
      <input
        id={coin.symbol}
        value={disabled ? usd : usd / coin.quotes['USD'].price}
        type="number"
        onChange={onChange}
        disabled={!disabled}
      />
    </div>
    <button onClick={onClick}>Convert</button>
  </div>
);

 

disabled 값에 따라 보여지는 값과 disabled 속성을 다르게 함

 

자세한 내용은

2021.11.25 - [FrontEnd/React] - [ReactJS] ReactJS 로 영화 웹 서비스 만들기 (3) - Unit Converter 완성

을 참고하면 된다.

 

각 코인마다 다른 값을 가지므로

이름은 coin.symbol 을,

계산할 때는 coin.quotes['USD'].price 를

를 이용했다.

 

입력 값 => onChange

convert 버튼 => onClick

 

 

onChange, reset, onClick

const onChange = (event) => {
  setUSD(event.target.value);
};

const reset = () => {
  setUSD(0);
};

const onClick = () => {
  reset();
  setDisabled((current) => !current);
};

 

onChange : 입력된 값으로 update

 

reset : usd 값 0 으로 reset

 

onClick : convert 돼야 하므로 reset & setDisabled(!current)

 

 

전체 코드

더보기
import { useState, useEffect } from "react";

function Converter({coin}) {
  const [usd, setUSD] = useState(0);
  const [disabled, setDisabled] = useState(false);

  const onChange = (event) => {
    setUSD(event.target.value);
  };
  const reset = () => {
    setUSD(0);
  }
  const onClick = () => {
    reset();
    setDisabled((current) => !current);
  };

  return (
    <div>
      <div>
        <label htmlFor="USD">USD </label>
        <input
          id="USD"
          value={
            disabled ? usd * coin.quotes['USD'].price: usd
          }
          type="number"
          onChange={onChange}
          disabled={disabled}
        />
      </div>
      <div>
        <label htmlFor={coin.symbol}>{coin.symbol} </label>
        <input
          id={coin.symbol}
          value={disabled ? usd : usd / coin.quotes['USD'].price}
          type="number"
          onChange={onChange}
          disabled={!disabled}
        />
      </div>
      <button onClick={onClick}>Convert</button>
    </div>
  );
}

function CoinConverter() {
  const [loading, setLoading] = useState(true);
  const [coins, setCoins] = useState([]);
  const [index, setIndex] = useState("-1");
  const [selected, setSelected] = useState([]);
  useEffect(() => {
    fetch("https://api.coinpaprika.com/v1/tickers")
    .then((response) => response.json())
    .then((json) => {
      setCoins(json);
      setLoading(false);
    });
  }, []);
  const onSelect = (event) => {
    setIndex(event.target.value);
    if (event.target.value === "-1"){
      setSelected([]);
    }
    else {
      setSelected(coins[event.target.value]);
    }
  }
  return (
    <div>
      <h1>The Coin Converter {loading ? "" : `(${coins.length})`}</h1>
      {loading ? (
        <strong>Loading...</strong>
      ) : (
        <div>
          <select value={index} onChange={onSelect}>
            <option key="-1" value="-1">Select Coin</option>
            {coins.map((coin, idx) => (
              <option key={idx} value={idx}>
                {coin.name}
              </option>
            ))}
          </select>
          <hr />
          {index === "-1" ?
            ("Please Select Coin")
            :
            (<Converter coin={selected} />)
          }
        </div>
      )}
    </div>
  );
}

export default CoinConverter;

 

 


 

 

직접 과제를 구현해보니 더 유익한 시간이었다.

useState 와 useEffect 의 활용을 제대로 해볼 수 있었음

 

다음부턴 진짜 찐!! Movie App 구현의 시간이다.

 

 

댓글