React

환전(환율) 계산기 만들기 ② FE

code10 2023. 3. 14. 14:48

FE : React , yarn

BE: Express, npm


FE 최종 코드

//App.js

import React, { useCallback, useEffect, useState } from "react";
import instance from "./API/instance";
import "./App.css";
import CurrencyBox from "./components/CurrencyBox";
import Spinner from "./components/Spinner";

function App() {
  const [data, setData] = useState([]);
  const [list, setList] = useState([]);
  const [date, setDate] = useState("");
  const [rate, setRate] = useState();
  const [money, setMoney] = useState(1);
  const [inputMoney, setInputMoney] = useState(true);
  const [currencyCodeFrom, setCurrencyCodeFrom] = useState("USD"); //from
  const [currencyCodeTo, setCurrencyCodeTo] = useState("KRW"); //to
  const [nationFrom, setNationFrom] = useState("미국 달러"); //from
  const [nationTo, setNationTo] = useState("대한민국 원"); //to

  let amount1, amount2;
  if (inputMoney) {
    amount1 = money;
    amount2 = money * rate;
  } else {
    amount2 = money;
    amount1 = money / rate;
  }

  const onChange1 = (e) => {
    const str = e.target.value;
    if (isNaN(str)) {
      setMoney(0);
    } else {
      const regex = /[^0-9.]+/g;
      const money = str.replace(regex, "");
      setMoney(money);
      setInputMoney(true);
    }
  };

  const onChange2 = (e) => {
    const str = e.target.value;
    if (isNaN(str)) {
      setMoney(0);
    } else {
      const regex = /[^0-9.]+/g;
      const money = str.replace(regex, "");
      setMoney(money);
      setInputMoney(false);
    }
  };

  const rateDB = useCallback(
    async () => {
      try {
        const response = await instance.post(`/api?from=${currencyCodeFrom}&to=${currencyCodeTo}`);
        setRate(response.data.exchangeRate);
        setDate(response.data.date);
      } catch (error) {
        console.log(error);
      }
    }, [currencyCodeFrom, currencyCodeTo]);
    

  const currencynNationDB = async () => {
    try {
      const response = await instance.get(`/currencynationlist`);
      const listData = Object.values(response.data);
      setData(listData);
      const nations = listData
        .map((v) => `${v.nation} ${v.currencyName}`)
        .sort();
      setList(nations);
    } catch (error) {
      console.log(error);
    }
  };

  const opt = list.map((v) => (
    <option value={v} key={v}>
      {v}
    </option>
  ));

  const handleSelected1 = (e) => {
    setNationFrom(e.target.value);
    for (let value of data) {
      const country = e.target.value.split(" ")[0];
      if (value.nation === country) {
        setCurrencyCodeFrom(value.currencyCode);
      }
    }
  };

  const handleSelected2 = (e) => {
    setNationTo(e.target.value);
    for (let value of data) {
      const country = e.target.value.split(" ")[0];
      if (value.nation === country) {
        setCurrencyCodeTo(value.currencyCode);
      }
    }
  };

  useEffect(() => {
    currencynNationDB();
    rateDB();
  }, [rateDB]);

  return (
    <>
      <div className="wrap">
        <header>
          <h1>환전 계산기</h1>
          {!rate? <Spinner/>: null}
          <p>{date}</p>
        </header>
        <div className="currency-box">
          <CurrencyBox
            name="input1"
            opt={opt}
            selectedNation={nationFrom}
            handleSelected={handleSelected1}
            money={amount1}
            onChange={onChange1}
          />
          <CurrencyBox
            name="input2"
            opt={opt}
            selectedNation={nationTo}
            handleSelected={handleSelected2}
            money={amount2}
            onChange={onChange2}
          />
        </div>
      </div>
      <p className="ref">
        환율 기준 참고 API:{" "}
        <a
          href="https://exchangerate.host/#/#docs"
          style={{ color: "gray" }}
          target="_blank"
          rel="noreferrer"
        >
          https://exchangerate.host/#/#docs
        </a>
      </p>
    </>
  );
}

export default App;

=> useEffect에서 warning이 있었는데, 고치려고 하면 rateDB에서 warning(노란 줄)이 발생하고... useCallback으로 해결할 수 있었다.

//components/CurrencyBox.js

import React from "react";

function CurrencyBox(props) {
  const { opt, selectedNation, handleSelected, money, onChange,} = props;
  let amount
  amount = money.toLocaleString('ko-KR', {maximumFractionDigits: 2});
  return (
      <div className="input-box">
      <input type="text" min={0} onChange={onChange} value={amount} aria-label={selectedNation}/>
        <select value={selectedNation} onChange={handleSelected}>
        {opt}
      </select>
    </div>
  );
}

export default CurrencyBox;
//components/Spinner.js

import React from "react";

function Spinner(props){
  return(
    <div style={{margin: "auto", color: "#6f6f6f", opacity: "70%"}}>
      <h2>❤️로딩중❤️</h2>
    </div>
  )
}

export default Spinner;

=> 백엔드 코드 고치기 전에 rate 받아오는 게 너무 느려서 spinner를 만들었었다.

//API/instance.js

import axios from "axios"

const instance = axios.create({
  baseURL: "http://localhost:8080",
  timeout: 5000,
  headers: {
    "Access-Control-Allow-Origin": `http://localhost:8080`,
    'Access-Control-Allow-Credentials': "true",
  }
})

export default instance;

=> headers에 적용한 부분은 쿠키를 사용해 주고받는 게 없어서(? : 쿠키를 사용하면 FE, BE 둘 다 설정 필요하다는 글을 봤는데, 직접 확인해 보진 못함.) 불필요할지도 모르겠다. 백엔드에서 이미 해당 부분을 설정해놔서 그런지 headers 부분이 없어도 오류없이 잘 작동하는 것을 확인했다. prac이니 일단 기재해 놓음. timeout은 요청에 대한 시간 제한을 두는 건 좋으니까-!