[개인과제] 올림픽 메달 트랙커 만들기3

안현희·2024년 10월 31일
0

React를 배워보자!

목록 보기
9/20

과제를 마무리해보자.

  1. 국가추가시 국가명이 없을때는 추가되지 않게한다.
  2. 국가추가시 국가명이 숫자를 포함할때도 추가되지 않게한다.
  3. 국가추가시 국가명이 존재할때는 새로 추가하지않는다.
  4. 업데이트시 존재하지 않는 국가는 알려준다.
  5. 업데이트시 해당 국가만 업데이트가 되게 한다.
  6. 국가 추가 및 업데이트시 금메달 순으로 정렬한다.
  7. 메달입력시 양수만 가능하게 한다.
  8. 메달수는 최대 2자릿수까지만 되게한다.
  9. 메달입력시 "02"로 입력되어도 "2"로 입력되게 한다.
  10. 로컬스토리지
  • 해당 사항들을 구현해보자.

1. 국가추가시 국가명이 없을때는 추가되지 않게한다.

//App.jsx
  const addMedalData = (newData) => {
    const countryExists = medalData.some(
      (item) => item.country === newData.country
    );
    if (countryExists) {
      alert("해당 국가가 이미 존재합니다.");
      return;
    }
    setMedalData(sortedData);
  };
  • addMedalData에 로직을 작성했다.
    새로운 국가명의 입력값이 없을때, 알림창을 띄워준다.

2. 국가추가시 국가명이 숫자를 포함할때도 추가되지 않게한다.

//Editor.jsx
  const handleOnSubmit = (e) => {
    e.preventDefault();
    if (/\d/.test(formData.country)) {
      alert("국가명에는 숫자를 포함할 수 없습니다.");
      return;
    }
    addMedalData(formData);
    setFormData({ country: "", gold: 0, silver: 0, bronze: 0 });
  };
  • 정규표현식이 떠올랐고, 검색 후 handleOnSubmit에 로직을 작성했다.
  • /\d/ : 이 정규식은 0부터 9 사이의 숫자를 나타낸다.
  • .test() : 정규식과 함께 사용되는 메서드로, 주어진 문자열에 해당 패턴이 있는지 검사하여 true 또는 false를 반환한다.

3. 국가추가시 국가명이 존재할때는 새로 추가하지않는다.

//Editor.jsx
  const handleOnSubmit = (e) => {
    e.preventDefault();
    if (!formData.country) {
      alert("국가명을 입력해주세요.");
      return;
    }
    addMedalData(formData);
    setFormData({ country: "", gold: 0, silver: 0, bronze: 0 });
  };
  • 마찬가지로 handleOnSubmit에 로직을 작성했다.
  • input값이 없을때 위와 같은 알림창을 띄워준다.

4. 업데이트시 존재하지 않는 국가는 알려준다.

//App.jsx
  const updateMedalData = (updatedData) => {
    const countryExists = medalData.some(
      (item) => item.country === updatedData.country
    );
    if (!countryExists) {
      alert("존재하지 않는 국가입니다. 다시 확인해주세요.");
      return;
    }
  };
  • medalDataupdatedDatacountry값을 비교해서
    같은것이 존재하지 않을때, 알림창을 띄워준다.

5. 업데이트시 해당 국가만 업데이트가 되게 한다.

//App.jsx
  const updateMedalData = (updatedData) => {
    const updatedMedalData = medalData.map((item) =>
      item.country === updatedData.country ? updatedData : item
    );
    setMedalData(updatedMedalData);
  };
  • item.country === updatedData.country ? updatedData : item
    해당 국가명이 존재하면 updatedData를 반환하고,
    그렇지 않다면 기존의 데이터를 반환한다.

6. 국가 추가 및 업데이트시 금메달 순으로 정렬한다.

//App.jsx
// 추가시
  const addMedalData = (newData) => {
    const sortedData = [...medalData, newData].sort((a, b) => (b.gold - a.gold);
    setMedalData(sortedData);
  };

// 업데이트시
 const updateMedalData = (updatedData) => {
    const updatedMedalData = medalData
      .map((item) =>
        item.country === updatedData.country ? updatedData : item
      ).sort((a, b) => (b.gold - a.gold);
    setMedalData(updatedMedalData);
  };
  • 처음에는 금메달순으로 업데이트를 진행했는데, 불편한점이 눈에 보였다.

보통 메달 집계순위는 다음과 같다.

(출처 : 네이버 2024 파리올림픽 메달 순위)

  • 금메달 갯수가 많은쪽이 위로 올라가고
    그 다음은 은메달, 동메달 순인데 이 때 메달의 총 합계 또한 고려해야한다.

따라서 다음과 같이 로직을 수정했다.

//App.jsx
  const addMedalData = (newData) => {
    const sortedData = [...medalData, newData].sort((a, b) => {
      if (a.gold !== b.gold) return b.gold - a.gold;
      const totalA = a.gold + a.silver + a.bronze;
      const totalB = b.gold + b.silver + b.bronze;

      if (totalA !== totalB) return totalB - totalA;
      if (a.silver !== b.silver) return b.silver - a.silver;
      return b.bronze - a.bronze;
    });
    setMedalData(sortedData);
  };
  • 우리가 많이보던 메달 집계 방식으로 정렬된다.
  • 업데이트 로직에도 마찬가지로 넣어줬다.

7. 메달입력시 양수만 가능하게 한다.

//EditorItem.jsx
<input min="0">
  • 놀랍게도 이게 전부다.
    최소값을 0으로 설정하면서, 음수로는 입력이 되지 않는다.

8. 메달수는 최대 2자릿수까지만 되게한다.

처음에는 간단하게 maxLength로 하면 되겠지 싶어서 입력을 했는데,
작동이 되지 않았다. 참고문서
참고문서를 보고나서 로직을 작성해보았다.

//EditorItem.jsx
        <input
          type={type}
          placeholder={placeholder}
          name={name}
          value={value}
          min="0"
          onChange={onChange}
          onInput={
            name !== "country"
              ? (e) => {
                  if (e.target.value.length > e.target.maxLength) {
                    e.target.value = e.target.value.slice(
                      0,
                      e.target.maxLength
                    );
                  }
                }
              : undefined
          }
          maxLength={name !== "country" ? 2 : undefined}
        />           

prettier issue...

  • 이제 최대 2자릿수 이상으로 올라가지 않는다.

9. 메달입력시 "02"로 입력되어도 "2"로 입력되게 한다.

//Editor.jsx
  const handleOnChange = (e) => {
    const { name, value } = e.target;
    setFormData({
      ...formData,
      id: new Date().getTime(),
      [name]: name === "country" ? value : Math.min(parseInt(value, 10)),
    });
  };
  • parseInt를 사용하여 간단히 해결했다.

10. 로컬스토리지

//App.jsx
  useEffect(() => {
    const storedMedalData = localStorage.getItem("medalDatas");
    if (storedMedalData) {
      setMedalData(JSON.parse(storedMedalData));
    }
  }, []);

  useEffect(() => {
    localStorage.setItem("medalDatas", JSON.stringify(medalData));
  }, [medalData]);
  • 예습한 내용이 있어서, useEffect로 로직을 작성했다.

➕ 10-1. 피드백에 따른 로직수정

  const [medalData, setMedalData] = useState(() => {
    const storedMedalData = localStorage.getItem("medalDatas");
    return storedMedalData ? JSON.parse(storedMedalData) : [];
  });

  useEffect(() => {
    localStorage.setItem("medalDatas", JSON.stringify(medalData));
  }, [medalData]);
  • useEffect의 마운트 순서가 보장되지 않기 때문에,
    get방식을 초기 값으로 useState설정해주는것이 더욱 안전하다고 하셨다.
    그에 따라 로직을 수정했다.

  • 순서에 대해 생각해본적이 없었기 때문에, 적잖은 충격이었지만
    이렇게라도 알 수 있었기에 감사했다.

  • 다음에는 절대 이런 실수를 하지말자!


배포 및 소스코드

배포한 사이트 링크
소스코드

  • vercel로 배포했다.

회고

이렇게 과제를 모두 마무리했다.
언제나 그렇듯이 쉽지만은 않았고 처음 로직을 작성할때의 스트레스가 아직도 생생하다.
그래도 포기하지않고 해냈다.
앞으로도 어제보다 더 발전한 내가 되기위해 최선을 다하자!

그럼이만

0개의 댓글