개인과제

리그오브레전드 정보앱(트러블 슈팅1🌟)

choijming21 2024. 10. 1. 18:06

1. 문제 발생❓

"use client";

import { Champion } from "@/types/Champion";
import { ChampionRotation } from "@/types/ChampionRotation";
import { getChampionRotation } from "@/utils/rioApi";
import { getChampionList } from "@/utils/serverApi";
import { useEffect, useState } from "react";

function RotationPage() {
  const [rotation, setRotation] = useState<ChampionRotation | null>(null);
  const [champions, setChampions] = useState<Champion[]>([]);
  const [loading, setLoading] = useState<boolean>(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        const [rotationData, championData] = await Promise.all([
          getChampionRotation(),
          getChampionList(),
        ]);

        setRotation(rotationData);
        setChampions(championData);
        console.log("로테이션 데이터", rotationData);
        console.log("챔피언 데이터", championData);

        // key값에 맞는 챔피언 목록
        const freeChampions: Champion[] =
          rotation?.freeChampionIds.flatMap((id) =>
            champions.filter((champion) => champion.key === id)
          ) ?? [];

        console.log("프리!!!!!!", freeChampions);
      } catch (error) {
        console.error("Error fetching data", error);
        setError("데이터를 불러오는 중 오류가 발생했습니다.");
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, []);

  if (loading) return <div>로딩 중...</div>;
  if (error) return <div>error: {error}</div>;

  return <div>로테이션 페이지</div>;
}

export default RotationPage;

 

< 문제점 >

  • 외부에서 rotationData, championData는 데이터를 잘 가져오지만, rotation에서 가져오는 id값과 champion에서 가져오는 key값이 일치하는 데이터만 뽑아서 새로운 freeChampions 배열을 만들어야하는데 freeChampions 배열이 타입이 맞지 않다고 오류가 뜨는 상황(Champion[] 타입에는 undefined가 허용되지 않음)
  • console.log("로테이션 데이터", rotationData)와 console.log("챔피언 데이터", championData)까지는 잘 나오지만 console.log("프리!!!!!!!", freeChampions)는 콘솔에 출력이 안되는 상황

 

 

 

 

 

 

2. 원인 추론 🔎

  • map 함수의 동작
    • rotationData.freeChampionIds 배열의 각 요소에 대하여 함수를 실행
    • 이 경우, 각 id에 대해 find 매서드를 실행
  • find 매서드의 특징
    • 조건에 맞는 첫 번째 요소를 반환
    • 조건에 맞는 요소가 없으면 undefined를 반환
  • 함수 동작 결과
    • champion 배열에서 첫 번째 요소를 찾지 못해  발생한 undefined 값들의 혼합
  • 타입 불일치
    • freeChampions의 타입은 Champion[]로 선언됨
    • 하지만 실제 결과는 Champion 또는 undefined 타입을 가지고 있는 배열

 

  • 결론: map과 find의 조합으로 인해 undefined를 포함할 수 있는 배열이 생성되어 선언된 Champion[] 타입과 불일치가 발생하여 TypeScript 오류가 발생한 것 같다.

 

 

 

 

 

 

 

 

 

 

3. 해결 과정 📋

왜 find 매서드가 rotationData의 id값과 championData의 key 값이 일치하는 첫 번째 요소를 찾을 수 없는지를 알아내는 것이 가장 중요한 해결책이 될 것 같다.

 

 

  • rotationData와 championData fetch애소 엔드 포인트를 활용해 응답값 확인해보기
    • champion.key는 문자열(string) 타입
    • id는 숫자(number) 타입
  • 해결 시도
    • "champion.key === String(id)"로 수정
    • String()을 사용해서 숫자 id를 문자열로 변환해줌

 

        // key값에 맞는 챔피언 목록
        const freeChampions: Champion[] =
          rotation?.freeChampionIds.map((id) =>
            champions.find((champion) => champion.key == String(id))
          ) ?? [];

 

  •  filter 매서드 사용하여 undefined값 제거
    • 또한, rotationData.freeChampionIds와 championData가 항상 완벽하게 일치한다고 보장할 수 없기에 안전 장치로 filter 매서드를 사용하여 undefined 값을 걸러내주었다.
      // key값에 맞는 챔피언 목록
        const freeChampionList: Champion[] = rotationData?.freeChampionIds
          .map((id) =>
            championData.find((champion) => champion.key === String(id))
          )
          .filter((champion): champion is Champion => champion !== undefined);

        setFreeChampions(freeChampionList);

 

 

 

 

 

 

 

 

4. 결과 ❤‍🔥

  • id를 (숫자 -> 문자열)로 변경해주어 find를 사용해 일치하는 요소를 찾을 수 있었다.
  • 만약을 대비해 filter 사용으로 undefined값은 제거해 주어 타입 불일치 오류를 없앨 수 있다.