[1차] Next.js 리그오브레전드 정보 프로젝트 (초기 세팅)
[1차] Next.js 리그오브레전드 정보 프로젝트
베포 링크
- vercel
- github
- https://github.com/rarrit/lol-info-app
- branch
- setup
- feat/champion
프로젝트 설명
NextJS와 TypeScript을 사용하고 Riot API를 활용하여 리그오브레전드의 다양한 데이터를 조회하고 이를 기반으로 생성한 프로젝트 입니다.
STACK
프로젝트 구조
- 1차에선 프로젝트 초기 세팅 및 API 세팅을 했습니다.
전체 프로젝트 구조
📦app┣ 📂_components
┃ ┣ 📂champions
┃ ┃ ┣ 📜ChampionCard.tsx
┃ ┃ ┗ 📜ChampionList.tsx
┃ ┗ 📂items
┃ ┃ ┣ 📜itemCard.tsx
┃ ┃ ┣ 📜itemDesc.tsx
┃ ┃ ┗ 📜itemList.tsx
┣ 📂api
┃ ┣ 📂rotation
┃ ┃ ┗ 📜route.ts
┃ ┗ 📜apiKey.ts
┣ 📂champions
┃ ┣ 📂[id]
┃ ┃ ┗ 📜page.tsx
┃ ┣ 📜layout.tsx
┃ ┣ 📜loading.tsx
┃ ┗ 📜page.tsx
┣ 📂fonts
┃ ┣ 📜GeistMonoVF.woff
┃ ┗ 📜GeistVF.woff
┣ 📂items
┃ ┣ 📜loading.tsx
┃ ┗ 📜page.tsx
┣ 📂rotation
┃ ┣ 📜loading.tsx
┃ ┗ 📜page.tsx
┣ 📂types
┃ ┣ 📜Champion.ts
┃ ┣ 📜ChampionRotation.ts
┃ ┗ 📜Item.ts
┣ 📂utils
┃ ┣ 📜riotApi.ts
┃ ┗ 📜serverApi.ts
┣ 📜favicon.ico
┣ 📜global-error.tsx
┣ 📜globals.css
┣ 📜layout.tsx
┣ 📜loading.tsx
┗ 📜page.tsx
디렉토리 설명
4-1) app > _components
공통 컴포넌트 디렉토리, 초기 세팅 및 1차 작업에서는 챔피언 위주로 작업해서 ItemList 추가할 예정이다.
-
ChampionList.tsx
: 챔피언 리스트 -
ChampionCard.tsx
: 챔피언 리스트에 출력될 챔피언 카드 -
ItemList.tsx
: 아이템 리스트 -
ItemCard.tsx
: 아이템 카드
4-2) app > api
api key값과 챔피언 로테이션 라우터 핸들러를 세팅해줬다.
4-3) app > utils
초기 api 세팅 디렉토리, api 관련 세팅을 해줬다.
-
serverApi.ts
: API 최신 버전, 아이템, 챔피언 최신 정보를 가져오고 해당 버전에 맞는 데이터를 요청하여 반환함
4-4) app > champions
챔피언 리스트, 챔피언 상세페이지, 해당 페이지에서 최신 챔피언 리스트를 조회할 수 있으며, 클릭해서 상세 정보를 확인할 수 있다.
4-5) app > items
아이템 리스트, 아이템 상세페이지, 해당 페이지에서 리그오브레전드의 아이템 리스트를 확인할 수 있다.
4-6) app > rotation
매주 무료로 플레이할 수 있는 챔피언들의 목록을 확인할 수 있다.
4-7) app > layout.tsx
공통 헤더 및 푸터 를 생성 후 헤더에 챔피언,아이템,로테이션 메뉴를 생성
4-8) app > types
이번 프로젝트에서 사용할 정보를 정의한 타입 인터페이스다.
작업 목록
5-1) 환경변수 파일 생성 및 세팅
next.js로 프로젝트 생성 후 처음으로 한 작업이다.
-
.env
환경 변수 파일 생성- 해당 파일에서 자주 사용될 api key값과 base url을 정의해주었다.
-
app > api > apiKey.ts
파일을 생성- 해당 파일에서
RIOT_API_KEY
,RIOT_BASE_URL
변수를 생성 후 export 해줌
- 해당 파일에서
export const RIOT_API_KEY = process.env.NEXT_PUBLIC_RIOT_API_KEY;
export const RIOT_BASE_URL = process.env.NEXT_PUBLIC_RIOT_URL;
5-2) 레이아웃 설정
두 번째로 레이아웃을 설정해주었다.
- header, footer 생성
- 이번 프로젝트에서 사용하는 페이지 Link 설정
- 작업하면서 편하게 페이지를 확인할 수 있게 미리 설정해주었다.
- 초기 세팅 이후 스타일 및 추가 컨텐즈 적용 예정
import type { Metadata } from "next";
import localFont from "next/font/local";
import "./globals.css";
import Link from "next/link";
const geistSans = localFont({
src: "./fonts/GeistVF.woff",
variable: "--font-geist-sans",
weight: "100 900",
});
const geistMono = localFont({
src: "./fonts/GeistMonoVF.woff",
variable: "--font-geist-mono",
weight: "100 900",
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
<header id="header">
<div className="inner">
<div id="logo">
<Link href="/">홈</Link>
</div>
<nav>
<ul>
<li><Link href="/rotation">Rotation</Link></li>
<li><Link href="/champions">Champions</Link></li>
<li><Link href="/items">Items</Link></li>
</ul>
</nav>
</div>
</header>
{children}
<footer id="footer">
<div className="inner">
푸터
</div>
</footer>
</body>
</html>
);
}
5-3) 데이터 확인 및 Type 정의
처음 데이터를 어떻게 확인해야 할지 고민하던 중 같은 조원의 도움으로 API 정리가 잘 되어있는 블로그 - 롤 API 활용을 위한 정보를 알게되었다. 해당 블로그에서 최신 버전의 값을 매칭해서 데이터를 확인 후 타입을 정의해주었다.
- 블로그에서 챔피언, 아이템 데이터를 확인
- app > types 폴더 생성 및 각 타입의 ts 파일 생성
- Champion.ts
- ChampionRotation.ts
- Item.ts
- 사용할 데이터의 타입을 적용해주었다.
// app > types > Item.ts
export interface ItemType {
name: string;
description: string;
plaintext: string;
image: {
full: string;
sprite: string;
};
gold: {
total: number;
};
}
5-4) 최신 버전 함수 생성
- 이번 프로젝트에서 가장 많이 재사용될 최신 버전을 반환하는 함수를 만들어 주었다.
- 해당 json을 들어가면, 배열로 모든 버전을 확인할 수 있으며 가장 최신 버전을 가져오기 위해 배열의 첫 번째 인덱스를 반환해주었다.
// app > utils > serverApi.ts
export const getLatestVersionUrl = async () => {
const latestVersions = `${RIOT_BASE_URL}/api/versions.json`;
const res = await fetch(latestVersions);
const version: string[] = await res.json();
const latestVersion = version[0];
return latestVersion;
}
5-5) 챔피언 리스트 페이지 설정
챔피언 리스트 페이지에서는 ChampionList
비동기 컴포넌트를 정의하고 렌더링한다.
import ChampionList from "../_components/champions/ChampionList"
const ChampionPage = async () => <ChampionList/>
export default ChampionPage
5-6) 챔피언 리스트 컴포넌트 설정
Riot API에서 가져온 챔피언 데이터를 기반으로 챔피언 목록을 화면에 렌더링한다.
- 렌더링 방식: ISR
- 재검증 시간(revalidate)은 하루(86400초)로 정의한다.
- 챔피언 데이터를 가져오는 함수 생성
- fetch를 사용해서, 최신 버전의 챔피언 리스트를 반환하는 함수를 생성했다.
- props로 데이터 전달
- 해당 데이터를
ChampionCard
컴포넌트로 전달해줌
- 해당 데이터를
// app > utils > serverApi.ts
export const getChampions = async () => {
try {
const latestVersion = await getLatestVersionUrl();
const res = await fetch(`${RIOT_BASE_URL}/cdn/${latestVersion}/data/ko_KR/champion.json`, {
next: {
revalidate: 86400,
}
});
const data = await res.json();
const championList: ChampionInfo[] = Object.values(data.data);
return championList;
} catch (error) {
console.error('챔피언 데이터 가져오기 오류:', error);
throw error; // 오류를 다시 던져 호출자에게 알림
}
};
// app > _components > ChampionList
import { getChampions } from "@/app/utils/serverApi";
import ChampionCard from "./ChampionCard";
const ChampionList = async () => {
const champions = await getChampions();
return (
<div id="championList" className="flex flex-wrap">
{
champions.map(champion => {
return (
<ChampionCard
key={champion.id}
champion={champion} // champion prop 전달
/>
);
})
}
</div>
);
}
export default ChampionList;
5-7) 챔피언 카드
챔피언의 이름,타이틀,이미지 등 화면에 표시하는 역할을 하는 컴포넌트이다.
- prop 타입 정의
-
ChampionCardProps
: 해당 컴포넌트가 받을champion
prop 타입을 정의함
-
- 컴포넌트 타입 정의
-
React.FC
: Function Component 타입의 줄임말로, React + Typescript 조합으로 개발할 때 사용하는 타입이다.
- 함수형 컴포넌트 사용 시 타입 선언에 쓸 수 있도록 React에서 제공하는 타입.
-
// app > _components > ChampionList
import { RIOT_BASE_URL } from "@/app/api/apiKey";
import { ChampionInfo } from "@/app/types/Champion";
import Image from "next/image";
import Link from "next/link";
type ChampionCardProps = {
champion: ChampionInfo; // champion prop을 정의
};
const ChampionCard: React.FC<ChampionCardProps> = ({ champion }) => {
return (
<div>
<h2>{champion.name}</h2>
<p>{champion.title}</p>
{champion.image && (
<Image
src={`${RIOT_BASE_URL}/cdn/img/champion/splash/${champion.id}_0.jpg`}
width={256}
height={151}
alt={champion ? champion.name : "챔피언 이미지"}
/>
)}
<Link href={`/champions/${champion.id}`}>상세페이지</Link>
</div>
);
};
export default ChampionCard;
회고
처음 진행하는 타입스크립트 + Next.js 프로젝트.. 아직 너무 손에 안익어서 세팅만 몇 시간이 걸린지 모르겠다. 이번 개인과제 기간은 널널하니 느리더라도 완료할 수 있도록 노력해보려 한다.
Keep - 현재 만족하고 있는 부분
API를 세팅하는 과정에서 어려움이 있었지만 화면에 최신 챔피언 리스트를 잘 뿌려준 것
Problem - 불편하게 느끼는 부분
타입스크립트가 생각보다 많이 어렵게 느껴진다. 처음 데이터를 확인하고 세팅했지만, 함수를 통해 반환하는 과정에서 데이터가 어떻게 반환하는지 잘 확인해야 했으며, 익숙하지 않아서 실수가 많았다.
Try - problem에 대한 해결책, 당장 실행 가능한 것
Thunder Client를 사용해서, 데이터를 잘 확인하고 타입을 작성해주는 것이 현재로선 최선의 해결책..일까..? TypeScript와 Next.js를 공부하고 처음 진행하는 프로젝트라 어려움이 많지만 어쩔 수 없다. 많이 사용해보며 익숙해지도록 노력해야겠다.