본문 바로가기
📄Today I Learned

Static Site Generation에서 객체 키를 다룰 때의 문제 해결

by 영진학생 2025. 3. 13.

오늘은 Static Site Generation(SSG) 방식으로 데이터를 불러와 아이템 리스트 페이지를 구현하는 것이 목표였다.

데이터를 가져오는 과정에서 예상치 못한 객체 구조 때문에 접근에 어려움을 겪었지만, 튜터님과 같이 공부하는 친구들의 도움으로 Object.entries를 활용하여 해결했다 :)


💡문제 발생

아이템 리스트를 가져오기 위해 fetch를 사용하여 데이터를 요청했고 API 요청 함수는 다음과 같다.

export const fetchVersions = async () => {
  const BASE_URL = process.env.BASE_URL;
  const response = await fetch(`${BASE_URL}/api/versions.json`);
  const data = await response.json();

  return data;
};

export const fetchItemList = async () => {
  const versions = await fetchVersions();
  const response = await fetch(
    `${BASE_URL}/cdn/${versions[0]}/data/en_US/item.json`
  );
  
  const data = await response.json();

  if (!response.ok) throw new Error(`HTTP request error:${response.status}`);

  return data;
};

그리고 데이터를 콘솔에 출력해보니

내 예상과는 다른 구조였다.

 

내가 원했던건 data 라는 이름의 객체안에 들어있는 객체들 이었는데 조금 당황스러운 형태로 나와서.

공식 Riot Developer Portal 홈페이지를 이용해 객체의 형태를 확인해 봤다.
https://ddragon.leagueoflegends.com/cdn/15.5.1/data/en_US/item.json

 

 

전혀 뜻밖의 형태를 띄고 있었는데 data 객체 안에 name, image 같은 category가 있는게 아니라 왠 숫자가 길을 막고 있잖아?

 

vscode로 가져와보면

{
  "1001": {
    "name": "Boots",
    "plaintext": "Slightly increases Move Speed",
    "image": { "full": "1001.png" },
    "gold": { "total": 300 }
  },
  "1004": {
    "name": "Faerie Charm",
    "plaintext": "Slightly increases Mana Regen",
    "image": { "full": "1004.png" },
    "gold": { "total": 200 }
  }
}

이런 모양을 띄는데.. 일반적인 배열이 아니라 숫자 키를 가진 객체 형태였다.

따라서 data.key.name과 같은 방식으로 접근하려고 했지만😅

당연히 작동하지 않았다. 객체 내부의 키가 동적인 숫자였기 때문이다.


🔑해결 방법

이 문제를 해결하기 위해 Object.entries 메서드를 사용했다. Object.entries(data)는 객체의 키-값 쌍을 배열 형태로 변환해준다. 이를 활용하여 숫자 키를 id 필드로 변환할 수 있었다.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries

const items = Object.entries(data).map(([id, value]) => ({
  id,
  ...value,
}));

위의 과정을 거치면 이제 items 배열 안에는 각 아이템이 다음과 같은 형태로 정리된다.

[
  {
    "id": "1001",
    "name": "Boots",
    "plaintext": "Slightly increases Move Speed",
    "image": { "full": "1001.png" },
    "gold": { "total": 300 }
  },
  {
    "id": "1004",
    "name": "Faerie Charm",
    "plaintext": "Slightly increases Mana Regen",
    "image": { "full": "1004.png" },
    "gold": { "total": 200 }
  }
]

저 고유의 숫자를 id로 지정해서 map 메서드를 사용할 때에도 key 속성으로 item.id 값을 사용할 수 있다.

<div className="w-full min-h-screen p-4 bg-gray-800 text-white">
  <div className="container mx-auto">
    <h1 className="text-2xl font-bold mb-4">Item List</h1>
    <div className="flex flex-wrap justify-center gap-4">
      {items.map((item) => (
        <li
          key={item.id}
          className="border rounded-lg shadow-md p-4 flex flex-col items-center text-center w-40 h-60 bg-gray-900"
        >
          <Image
            src={`${BASE_URL}/cdn/${versions[0]}/img/item/${item.image.full}`}
            alt={item.name}
            width={100}
            height={100}
            className="mb-2"
          />
          <h2 className="text-lg font-semibold">{item.name}</h2>
          <p className="text-sm text-gray-500 overflow-hidden text-ellipsis line-clamp-3">{item.plaintext}</p>
        </li>
      ))}
    </div>
  </div>
</div>

 

그리고 약간의 스타일링을 더해주면~

기본적인 아이템 리스트 UI 성공 😊


📝배운점

  • API 응답이 예상과 다르게 숫자 키를 가진 객체로 되어 있었다.
  • data.key.name 방식이 아닌 Object.entries(data).map()을 사용해야 했다.
  • Object.entries를 활용해 객체를 배열 형태로 변환함으로써 원하는 데이터를 추출할 수 있었다.

이 문제를 해결하면서 Object.entries의 유용성을 다시 한번 깨달았고, JSON 데이터 구조를 올바르게 이해하는 것이 중요하다는 점을 배웠다!