React

React로 Coin Tracker 만들기 💰

yunieyunie 2023. 5. 10. 14:40

달러를 입력하면 그걸로 암호화폐를 얼만큼 살 수 있는지 계산해주는 coin tracker를 만들어보자.

https://api.coinpaprika.com/v1/tickers API를 사용했다.

 

import { useEffect, useState } from "react";

function App() {
  const [loading, setLoading] = useState(true);
  const [coins, setCoins] = useState([]);
  const [money, setMoney] = useState();
  const [price, setPrice] = useState();
  const onChange = (event) => {
    setMoney(event.target.value);
  };
  const onSelect = (event) => {
    setPrice(event.target.value);
  };

  useEffect(() => {
      .then((response) => response.json())
      .then((json) => {
        setCoins(json);
        setLoading(false);
      });
  }, []);

  return (
    <div>
      <h1>The coins! ({coins.length})</h1>
      {loading ? <strong>loading...</strong> : null}
      <label htmlFor="dollars">dollar</label>
      <input
        value={money}
        id="dollars"
        placeholder="How much"
        type="number"
        onChange={onChange}
      />
      <select onChange={onSelect} defaultValue="">
        <option value="" disabled>
          Select coins
        </option>
        {coins.map((coin) => (
          <option value={coin.quotes.USD.price} key={coin.id}>
            {coin.name} ({coin.symbol}): ${coin.quotes.USD.price}USD
          </option>
        ))}
      </select>
      <hr />
      {money && price ? (
        <div>You can get {money / price}</div>
      ) : (
        <div>Enter a number and select coins</div>
      )}
    </div>
  );
}

export default App;

useState 훅을 사용하여, 컴포넌트의 상태를 관리한다.
loading: 코인 데이터를 로딩중인지 여부를 나타내는 boolean 값
coins: 코인 데이터를 담은 배열
money: 사용자가 입력한 달러 값을 담은 변수
price: 사용자가 선택한 코인의 가격을 담은 변수


useEffect 훅을 사용하여, 컴포넌트가 마운트되면 https://api.coinpaprika.com/v1/tickers 주소로 GET 요청을 보내어 코인 데이터를 가져오고, 그 결과를 setCoins 함수를 사용하여 coins 상태에 저장한다.

데이터 로딩이 완료되면 setLoading 함수를 사용하여 loading 상태를 false로 바꾼다.

화면에는 코인 데이터의 개수와 로딩중인지 여부를 나타내는 타이틀과, 사용자가 입력한 달러 값을 입력받는 input 요소, 코인 종류를 선택하는 select 요소를 렌더링한다.

onChange 함수가 input 요소에 바인딩되어 있어, 사용자가 값을 입력할 때마다 money 상태를 업데이트한다.

마찬가지로 onSelect 함수가 select 요소에 바인딩되어 있어, 사용자가 코인을 선택할 때마다 price 상태를 업데이트한다.

마지막으로 money와 price가 모두 값이 있는 경우에는 money / price를 계산하여 화면에 표시한다.

그렇지 않은 경우, 즉 사용자가 입력한 값이 하나라도 없는 경우에는 "Enter a number and select coins" 문구를 보여준다.

기본값으로는 코인을 선택하지 않은 경우를 대비하여 value 속성에 빈 문자열('')을 설정한다.

또한 select 요소의 defaultValue 속성을 이용하여 코인을 선택하지 않은 경우 기본값으로 'Select coins'가 선택되도록 한다.

 

 

그런데 이 코드를 실행하면 다음과 같은 warning이 뜬다.

Warrning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. 


이 경고는 React에서 "제어 컴포넌트"와 "비제어 컴포넌트"라는 두 가지 종류의 입력 요소가 있다는 것과 관련이 있다.
제어 컴포넌트는 React state를 사용하여 입력 요소의 값을 관리하는 반면, 비제어 컴포넌트는 DOM에서 직접 값을 가져오고 관리한다.
따라서 이 경고는 입력 요소에 초기 값을 설정하지 않았을 때 발생할 수 있다.

이 경우, React는 컴포넌트가 마운트될 때 입력 요소의 값을 자동으로 설정하려고 시도한다.

하지만 초기 값이 설정되지 않은 경우, 입력 요소는 비제어 상태에서 제어 상태로 변경되며 경고가 발생한다.
해결 방법은 초기 값을 빈 문자열("")로 설정하는 것이다.

따라서 다음과 같이 코드를 변경하면 경고가 뜨지 않는다.

  const [money, setMoney] = useState("");