해커랭크에 있는 React 문제 중 Data Handling에 관한 문제 CryptoRank ExChange를 풀어보았다.

1. 문제 개요
React로 암호화폐 환전 계산기를 만드는 문제이다. 사용자가 USD 금액을 입력하면 각 암호화폐로 몇 개의 코인을 받을 수 있는지 계산해서 테이블에 보여준다.
2. 핵심 요구사항
2.1 초기 상태
- input은 비어있고 에러 메시지 없음
- Number of Coins 컬럼은 0.00000000 표시
2.2 유효성 검사 (3가지 에러)
| 상황 | 에러 메시지 |
| input이 비어있을 때 | Amount cannot be empty |
| 0.01 미만 입력 | Amount cannot be less than $0.01 |
| 잔액(17042.67) 초과 | Amount cannot exceed the available balance |
2.3 코인 수 계산
Number of Coins = Amount × Exchange Rate (소수점 8자리)
2.4 주의해야할 점
- 처음 렌더링 시에는 에러 없음 → input을 한 번 입력 후 지웠을 때만 "empty" 에러 표시
- 숫자 에러(음수, 초과)일 때 → n/a
- empty 에러일 때 → n/a가 아닌 0.00000000 표시
3. 구현
3.1 상태 설계
const [amount, setAmount] = useState("");
const [touched, setTouched] = useState(false);
amount는 input 값, touched는 사용자가 input을 한 번이라도 조작했는지 여부를 저장한다. touched가 필요한 이유는 초기 렌더링 시 input이 비어있어도 에러를 보여주면 안 되기 때문이다.
3.2 유효성 검사
const getError = () => {
if (amount === "") return touched ? "Amount cannot be empty" : "";
if (parseFloat(amount) < 0.01) return "Amount cannot be less than $0.01";
if (parseFloat(amount) > BALANCE) return "Amount cannot exceed the available balance";
return "";
};
3가지 에러를 순서대로 검사한다.
- amount === "" 일 때 touched가 false면 빈 문자열을 반환해 에러를 숨긴다. 사용자가 값을 입력했다가 지웠을 때(touched === true)만 "Amount cannot be empty"를 반환한다.
- 0.01 미만이면 최솟값 에러
- 잔액(17042.67) 초과면 잔액 초과 에러
3.3 n/a와 0.00000000 구분
const isEmpty = amount === "";
const validAmount = !error && !isEmpty ? parseFloat(amount) : "";
<Table amount={validAmount} hasError={!!error && !isEmpty} />
에러가 있더라도 empty 에러인지 숫자 에러인지를 구분해야 한다.
| 상태 | hasError | amount | 코인 표시 |
| 초기/empty | false | "" | 0.00000000 |
| 음수/초과 | true | "" 아님 | n/a |
| 정상 입력 | false | 숫자 | 계산값 |
!isEmpty를 hasError에 추가해 empty 상태일 때는 hasError=false로 넘긴다.
3.4 코인 수 계산
const getCoins = (rate) => {
if (hasError) return "n/a";
if (amount === "") return "0.00000000";
return (amount * rate).toFixed(8);
};
- hasError가 true면 → "n/a"
- amount가 비어있으면 → "0.00000000"
- 정상 입력이면 → amount × rate를 소수점 8자리로 계산
3.5 전체 코드
// Main.js
import React, { useState } from "react";
import Table from "./Table";
const BALANCE = 17042.67;
function Main() {
const [amount, setAmount] = useState("");
const [touched, setTouched] = useState(false);
const handleChange = (e) => {
setTouched(true);
setAmount(e.target.value);
};
const getError = () => {
if (amount === "") return touched ? "Amount cannot be empty" : "";
if (parseFloat(amount) < 0.01) return "Amount cannot be less than $0.01";
if (parseFloat(amount) > BALANCE) return "Amount cannot exceed the available balance";
return "";
};
const error = getError();
const isEmpty = amount === "";
const validAmount = !error && !isEmpty ? parseFloat(amount) : "";
return (
<div className="layout-column align-items-center mx-auto">
<h1>CryptoRank Exchange</h1>
<section>
<div className="card-text layout-column align-items-center mt-12 px-8 flex text-center">
<label>
I want to exchange ${" "}
<input
className="w-10"
data-testid="amount-input"
required
type="number"
placeholder="USD"
value={amount}
onChange={handleChange}
/>{" "}
of my ${BALANCE.toFixed(2)}:
</label>
{error && (
<p data-testid="error" className="form-hint error-text mt-3 pl-0 ml-0">
{error}
</p>
)}
</div>
</section>
<Table amount={validAmount} hasError={!!error && !isEmpty} />
</div>
);
}
export default Main;
// Table.js
import React from "react";
import { cryptocurrencyList } from "../cryptocurrency-list";
function Table({ amount, hasError }) {
const getCoins = (rate) => {
if (hasError) return "n/a";
if (amount === "") return "0.00000000";
return (amount * rate).toFixed(8);
};
return (
<div className="card card-text mt-10 mx-4">
<table className="mb-0">
<thead>
<tr>
<th>Cryptocurrency</th>
<th>Exchange Rate</th>
<th>Number of Coins</th>
</tr>
</thead>
<tbody data-testid="exchange-data">
{cryptocurrencyList.map((currency) => (
<tr key={currency.code}>
<td>{currency.name}</td>
<td>1 USD = {currency.rate} {currency.code}</td>
<td>{getCoins(currency.rate)}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default Table;'코딩테스트' 카테고리의 다른 글
| [프로그래머스] 피로도 (JS) (0) | 2026.05.09 |
|---|---|
| [프로그래머스] 가장 큰 수 (JS) (0) | 2026.05.06 |
| [프로그래머스] 파일명 정렬 (JS) (0) | 2026.03.28 |
| [프로그래머스] 노란불 신호등 (JS) (0) | 2026.03.21 |
| [백준] 스택 수열 (JS) (0) | 2025.08.13 |