트러블슈팅 - rotation 기능구현 (데이터 가져오기)

하영·2024년 10월 4일
1

Next.js

목록 보기
7/19

개인과제에서 rotation 페이지를 구현하면서 까다로운 과정을 겪게 되었다…🫠
현업에서 이런 경우가 많다고 해서… 미래의 나를 위한 정리글을 작성해보기로..했다..!

rotation 기능구현 (데이터 가져오기)

구현사항
rotation page의 페이지 설정은 아래와 같다.

  • 경로: /rotation
  • 기능: 현재 무료로 플레이 가능한 챔피언들을 표시
  • 렌더링 방식: 클라이언트 사이드 렌더링 (CSR)
    • 클라이언트에서 데이터를 가져와 렌더링

이 내용을 기반으로 api에서 어떤 데이터를 주는지 확인해보려고 코드를 작성했다.


01. 처음 작성한 코드 & 콘솔 확인 👩🏻‍💻

"use client"; //CSR 렌더링이므로 작성 필수!

import { useEffect, useState } from "react";
import { getChampionRotation } from "@/utils/riotApi";

export default function ChampionRotationPage() {
  const [rotation, setRotation] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchRotation() {
      try {
        const data = await getChampionRotation();
        console.log("API 응답 데이터:", data); // 콘솔확인
        setRotation(data);
        
      } catch (error) {
        console.error("Fetch Error:", error);
        setError("로테이션 데이터를 가져오는 중 문제가 발생했습니다.");
        
      } finally {
        setLoading(false);
      }
    }

    fetchRotation();
    
  }, []);

  if (error) {
    return <div>Error: {error}</div>;
  }

  if (!rotation) {
    return <div>Loading...</div>;
  }

  return (
    <div>
      <h1>챔피언 로테이션</h1>
    </div>
  );
}

콘솔창 확인하기 ✅

이렇게 작성하고 콘솔창을 확인했는데 난 내가 api 주소를 잘못 불러온 줄 알았다….ㅋㅋ

이름이라던가.. 뭐 캐릭터 설명도 없이 사진처럼 이상한 숫자만 주르륵 떴고 freeChampionIds 라는 내가 전혀 작성하지 않았던게 있어서 당황스러웠다.

튜터님한테 찾아가서 해결방법을 물어보았고… 꽤나 까다로운 작업이 될 수 있겠다는 생각이 들었다…ㅎ


02. 해결 방법 🔍

Champion 데이터를 주는 json api를 보면 위 사진처럼 캐릭터(Aatrox) 안에 데이터들이 쭉 담겨진 걸 볼 수 있다. 아까 봤던 숫자들은 그 주에 로테이션 된 캐릭터들의 고유 id 이기 때문에 그 id 값을 보고 전체 캐릭터 목록 데이터에서 일치하는 걸 찾아줘야한다는거다.

💡 정리하면 다음과 같다.

  1. 업데이트 된 로테이션 캐릭터 id를 확인 후 데이터 받아온다. → freeChampionIds
  2. Champion data 에서 동일한 값을 가진 것만 find 메소드로 찾아서 후 배열로 담는다.
  3. freeChampionIds 가 주는 데이터 타입은 number, Champion 데이터는 string이므로 형변환도 해야한다.

03. 수정한 코드 & 콘솔 확인 🚧

"use client";

import { useEffect, useState } from "react";
import { getChampionRotation } from "@/utils/riotApi";
import { fetchChampionList } from "@/utils/serverApi"; // 챔피언 목록

type ChampionData = { // 타입 명시하기
  id: string;
  title: string;
  name: string;
  image: { full: string };
};

export default function ChampionRotationPage() {
  const [rotation, setRotation] = useState<number[]>([]); // id , 배열로 담기
  const [champions, setChampions] = useState<{
    [key: string]: ChampionData;
  }>({}); // 챔피언 목록
  const [error, setError] = useState<string | null>(null);
  const [loading, setLoading] = useState<boolean>(true);

  useEffect(() => {
    async function fetchData() {
      try {
        const rotationData = await getChampionRotation();
        **console.log(rotationData); // ✅ 수정한 부분
        setRotation(rotationData.freeChampionIds);

        const championData = await fetchChampionList();
        **console.log(championData); // ✅ 수정한 부분
        setChampions(championData);
        
      } catch (error) {
        console.error("Fetch Error:", error);
        setError("로테이션 데이터를 가져오는 중 문제가 발생했습니다.");
        
      } finally {
        setLoading(false);
      }
    }

    fetchData();
  }, []);

  if (loading) {
    return <div>Loading...</div>;
  }

  if (error) {
    return <div>Error: {error}</div>;
  }

  return (
    <div>
      <h1>챔피언 로테이션</h1>
      <div>
        {rotation.map((id) => {
          const champion = Object.values(champions).find( //find 메소드 사용
            (champion) => champion.id === id.toString() //rotation의 id 문자열로변환
          );
          console.log(champion)

          if (!champion) {
            return null;
          }

          return (
            <div key={champion.id}>
              <img
                src={`https://ddragon.leagueoflegends.com/cdn/14.19.1/img/champion/${champion.id}.png`}
                alt={champion.name}
                width={100}
                height={100}
              />
              <h3>{champion.name}</h3>
              <p>{champion.title}</p>
            </div>
          );
        })}
      </div>
    </div>
  );
}

콘솔창 확인하기 ✅

우선 rotationchampions 에는 내가 받고자 하는 데이터가 잘 담겨져왔다.

이제 여기서 find 메소드로 일치하는 데이터만 뽑아오면 되었다!

return (
<div>
  <h1>챔피언 로테이션</h1>
  <div>
    {rotation.map((id) => {
      const champion = Object.values(champions).find( //find 메소드 사용
        (champion) => champion.id === id.toString() //rotation의 id 문자열로변환
      );
      console.log(champion)  // 🚨 undefined

      if (!champion) {
        return null;
      }
 
 // ** 생략 **
 )

그런데 자꾸 데이터가 뜨지 않았고 콘솔로 확인해보니까 champion 값이 undefined 가 떴다.

find 메소드를 적용하기 전의 데이터는 잘 불러와지는지 확인해봤다.

Object.values(champions) 데이터 확인 ✅

일단 전체 데이터는 원하는대로 잘 담겨져 왔고 문제는 find를 적용하는 부분이라는걸 확인했다.


04. find 적용 후 undefined 뜨는 이슈 해결 ✅

주석처리한 것처럼 코드를 작성해서 데이터를 확인했다.

튜터님 말대로 id 값을 비교하면 된다~ 해서 제대로 안 보고 id를 각각 비교했는데 콘솔로 보면 멍청한 짓을 하고 있었다는 걸 알 수 있다…

rotation에서는 id가 맞지만 champion 데이터에서 비교할 건 id가 아니라 key 값이었다… 😇

코드 재수정하기 🚧

// ** 중략 **

  return (
    <div>
      <h1>챔피언 로테이션</h1>
      <div>
        {rotation.map((id) => {
          console.log("로테이션 챔피언 ID:", id);
          const champion = Object.values(champions).find((champion) => {
            return champion**.key** === id.toString(); //id가 아니라 key!!
          });

          if (!champion) {
            return null;
          }

          return (
            <div key={champion.id}>
              <img
                src={`https://ddragon.leagueoflegends.com/cdn/14.19.1/img/champion/${champion.id}.png`}
                alt={champion.name}
                width={100}
                height={100}
              />
              <h3>{champion.name}</h3>
              <p>{champion.title}</p>
            </div>
          );
        })}
      </div>
    </div>
  );

이렇게 수정해주니까 기다렸다는듯이 촤라락 데이터가 브라우저에서 펼쳐졌다..ㅎ

늘 느끼는 교훈… api 데이터를 불러올 때는 콘솔을 꼼꼼하게 보자…!!

profile
왕쪼랩 탈출 목표자의 코딩 공부기록

0개의 댓글