본문 바로가기
💻JavaScript/Personal Project

메달 트래커 만들기

by 영진학생 2025. 1. 24.

 

📅 프로젝트 기간

2025.01.21 - 2025.01.24 (4일)

 

🔥느낀 점

이번에 리액트를 입문하면서 느낀 부분을 얘기하자면, 정말 효율적인 라이브러리라고 생각한다. 두 개의 가상 DOM으로 변경된 값을 비교하고 실제 DOM에 수정된 부분만 리렌더링 된다는 점에서 효율적이고 빠른 렌더링이 리액트를 사용하는 큰 이유이지 않을까? 그리고 컴포넌트로 재사용이 가능한 함수나 태그들을 묶어 여러번 사용할 수 있다는 점이 매력적으로 느껴졌다. BUT, 코딩 시작한지 1달정도 된 내가 이해하기엔 너무너무 어려웠다.. HTML CSS 기초지식 없이 자바스크립트를 배울때도 비슷한 느낌을 받았었지만 이번에 리액트를 입문하게되면서 또 새로운 벽을 맞닥뜨린 느낌이었다. 리액트는 선언형 프로그래밍 방식을 사용하기 때문에 멍령형인 자바스크립트와는 또 코드를 작성해 나가는 개념이 완전히 다르게 느껴져서 많이 해맸다고 생각한다. 하지만 리액트에 많이 익숙해 지고 내 스스로 원하는 웹을 만들 수 있게 된다면 그 자체로 너무 행복할것 같다.

 

//*--- state 생성 ---*//
  const [country, setCountry] = useState("");
  const [gold, setGold] = useState(0);
  const [silver, setSilver] = useState(0);
  const [bronze, setBronze] = useState(0);
  const [countries, setCountries] = useState([]);

 

국가, 금, 은, 동메달의 입력 값을 담을 state를 생성했다.

컴포넌트 내부에 State를 생성하고 State의 값이 변경되면 컴포넌트가 Rerendering 되는 개념이라고 한다.

다 만들고 나서 생각난 건데 여기에서 조금 아쉬운 부분이 하나의 스테이트에 초기값을 객체 형태로 넣었다면 굳이 이렇게 까지 여러 종류의 state를 만들지 않았을 수도 있었을 텐데 하는 아쉬움이 있었다.

 

//*--- 메달 개수를 상태변화함수에 전달하는 핸들러 ---*//
  const enterCountryHandler = (e) => { setCountry(e.target.value); };
  const goldCounterHandler = (e) => { setGold(e.target.value); };
  const silverCounterHandler = (e) => { setSilver(e.target.value); };
  const bronzeCounterHandler = (e) => { setBronze(e.target.value); };

 

입력 값을 받으면 각각 setState 상태변화 함수에 그 값의 상태를 업데이트 하는 핸들러 함수를 만들었다.

물론 이 부분도 공통적인 부분이 많아 하나의 함수로 묶을수 있으면 좋을거 같다 라는 의문이 들었다.

 

//*--- 국가 & 메달 추가하는 핸들러 ---*//
  const addCountryHandler = function (e) {
    // 새로고침 방지
    e.preventDefault();
    // 기존 국가들에 새롭게 추가할 국가 객체
    const newCountry = {
      id: crypto.randomUUID(),
      country: country,
      gold: gold,
      silver: silver,
      bronze: bronze,
    };
    // 금메달 갯수로 내림차순 하고 변수에 담아두기
    const goldRank = [...countries, newCountry].sort((a, b) => { return b.gold - a.gold; })
    // setCountries 상태변화함수 실행
    setCountries(goldRank);
    // 입력된 값을 초기화
    setCountry("");
    setGold(0);
    setSilver(0);
    setBronze(0);
  };

 

input에 입력 값을 넣으면 각각 국가들의 정보(id, country, gold, silver, bronze) 데이터를 가지고 있는 객체를 countries라는 배열에 추가하는 함수이다. id를 부여하는 부분이 조금 흥미로운데 기존에 new Date().getTime() 을 이용해 유일한 고유의 숫자 값을 id에 부여할수도 있지만 crypto.randomUUID() 를 사용하면 브라우저 환경에서 고유한 UUID를 생성할 수 있다. UUID는 Universally Unique Identifier라는 의미이며 전 세계적으로 고유한 식별자를 생성하는 표준이라고 한다. new Date().getTime() 방식보다 충돌 가능성이 훨씬 낮다는 장점이 있지만 브라우저 API로 설계되었기 때문에 Node.js에서도 사용할 순 있지만 crypto 모듈을 가져와야 한다.

 

//*--- 국가 메달 리스트 삭제하는 핸들러 --*//
  const deleteCountryHandler = (id) => {
    setCountries(countries.filter((country) => id !== country.id ));
  };

  //*--- 국가 업데이트 핸들러 ---*//
  const updateCountryHandler = (e) => {
    e.preventDefault();
    const updatedCountry = countries.map((newCountry) => 
      newCountry.country === country ? {...newCountry, country, gold, silver, bronze } : newCountry
    );
    setCountries(updatedCountry);
    setCountry("");
    setGold(0);
    setSilver(0);
    setBronze(0);
  };

 

e.preventDefault()는 폼 제출 기본 동작을 방지 하기위해 함수 최상단에 위치해야한다. 사용하지 않으면 form의 특성때문에 함수가 실행될 때 마다 페이지가 새로고침 되어버리는 불상사가 생긴다. 나열된 리스트에서 무엇인가를 제거하는 방법에는 filter 메서드가 가장 쉬운 방법이라는 것을 알게 되었다. filter로 우리가 부여한 고유의 아이디 값을 제외한 나머지 값만 리턴하게 되면 손쉽게 우리가 원하는 목표를 걸러낼수 있다. 추가로 기존에 입력된 국가의 메달 수를 갱신하는 업데이트 버튼인데, arr.length === arr.map().length 에서 힌트를 얻었다. map 메서드는 메서드를 사용하기 전 배열의 길이와 같은 길이의 배열을 반환하기 때문에 countries의 배열의 길이 즉 등록된 국가의 갯수에 영향을 주지 않고 값을 변경할 수 있다. newCountry의 국가명이 일치하면 기존 국가의 메달수를 갱신해주고 그렇지 않다면 본래 newCountry를 반환시켰다.