const [loading, setLoading] = useState(true);
const [coins, setCoins] = useState([]);
useEffect(() => {
fetch('https://api.coinpaprika.com/v1/tickers')
.then((res) => res.json())
.then((result) => {
setCoins(result);
setLoading(false);
});
}, []);
coins
라는 배열 안에 담아준다.👉 API 정보를 화면에 불러오기까지 시간이 걸린다. 정보를 받아오는 동안 사용자에게 'Loading' 표시를 보여주어 로딩중이라는 사실을 알려준다.
<h1>Coin Tracker {loading ? '' : `${coins.length}`}</h1>
true
을 넣어준다. loading 중인지 아닌지 판별하기 위함이다.loading
글씨가 보이게 하고, 아닐 경우에는 빈 텍스트를 보여준다. {loading ? (
<strong className='loading'>Loading...</strong>
) : (
<ol>
{coins.map((coin) => {
return (
<li key={coin.id}>
<strong>{coin.name} : </strong>
<span>{coin.quotes.USD.price.toFixed(2)} USD</span>
</li>
);
})}
</ol>
)}
map 함수
를 돌려 코인의 이름과, 가격을 리스트 형태로 보여주도록 한다.toFixed
메서드를 사용한다.👀 어떤 코인을 선택하느냐에 따라 변환 UI가 달라지기 때문에 2 부분으로 나눠서 컴포넌트화 시켜주었다.
title
과 select
태그 부분select
태그로 선택한 코인의 정보를 부모 컴포넌트로 부터 props
로 받아온다.<select value={index} onChange={onSelected}>
<option value='-1'>Select Coin</option>
{coins.map((coin, index) => {
return (
<option key={coin.id} value={index}>
{coin.name}
</option>
);
})}
</select>
<br />
{index === '-1' ? (
<span className='select'>----- Please Select Coin -----</span>
) : (
<Converter coin={selected} />
)}
Select Coin
부분은 임의로 index를 '-1'로 주어 중복되지 않도록 설정해주었다.Select Coin
부분을 선택했을 때는 혹은 첫 랜더링 후 초기화면에 ----- Please Select Coin -----
가 보이도록 설정해주었다.<div>
<label htmlFor='usd'>USD : </label>
<input
id='usd'
value={disabled ? usd * coin.quotes.USD.price : usd}
onChange={onChange}
type='number'
disabled={disabled}
/>
</div>
<div>
<label htmlFor={coin.symbol}>{coin.symbol} : </label>
<input
className='coinInput'
id={coin.symbol}
value={disabled ? usd : usd / coin.quotes.USD.price}
onChange={onChange}
type='number'
disabled={!disabled}
/>
</div>
<button onClick={onClick}>Convert</button>
useState
와useEffect
개념만 알면 쉽게 구현해낼 줄 알았다. 심지어 Converter 부분은 바로 어제 해봤던 부분이라 중복되서 금방할 줄 알았다. 하지만 사용자가 선택한select
태그를 어떻게 가져와야 할지 고민하느라 대부분의 시간을 보냈다. 결국 구글링을 통해 value값에 index을 넣어주고 배열의 index와 일치하면 보여주도록 하여 성공하였지만 이걸 스스로 생각하지 못해서 아쉽다.