๐ [ํฌ์ผ๋ชฌ ๋๊ฐ ํ๋ก์ ํธ] #2 – ํ๋ก์ ํธ ์ธํ & API ์ฐ๊ฒฐํ๊ธฐ
โ๏ธ ํ๋ก์ ํธ ๊ธฐ๋ณธ ์ธํ
๐น Next.js ํ๋ก์ ํธ ์์ฑ
npx create-next-app@latest pokedex
- 2025.6์ ๊ธฐ์ค next.js 15.3.3 ๋ฒ์
- TypeScript: โ Yes
- ESLint, Tailwind: โ Yes
- App Router: โ Yes
- src ๋๋ ํ ๋ฆฌ ์ฌ์ฉ: โ Yes
๐น Tailwind ์ ํ
- Tailwind css intellisense(vscode ํ์ฅํ๋ก๊ทธ๋จ) : tailwind ์๋ ์ถ์ฒ, ๋งจ์ฒ์์ ์คํ์ด์ค ์ ๋ ฅํ ์คํ๊ฐ๋ฅ
// ํ๋ฆฌํฐ์ด ์ค์น
npm install -D prettier prettier-plugin-tailwindcs
// prettier.config.js ์ต์๋จ ๋๋ ํ ๋ฆฌ์ ํ์ผ์์ฑ
module.exports = {
plugins: ["prettier-plugin-tailwindcss"],
};
- prettier-plugin-tailwindcss : ์ฝ๋ ์๋์ ๋ ฌ
next.js ์ค์น ์์๋ถํฐ tailwind ์ต์ ์ด ์๊ธฐ ๋๋ฌธ์ ๋ฐ๋ก ์ค์ ํ ํ์โ
๐น ํด๋ ๊ตฌ์กฐ ๊ฐ๋จํ๊ฒ ์ ๋ฆฌ
/src
/app
/page.tsx ← ํ ํ์ด์ง
/components ← UI ์ปดํฌ๋ํธ
/lib ← API ํธ์ถ ํจ์
/styles ← ์ ์ญ ์คํ์ผ (Tailwind ์ฌ์ฉ)
๐ GitHub ์ ์ฅ์ ์ฐ๊ฒฐ
๐น ์ด๊ธฐ ์ปค๋ฐ ๋ฐ ํธ์
git init
git remote add origin ์ฃผ์
git add .
git commit -m "init: ํ๋ก์ ํธ ์ด๊ธฐ ์ค์ "
git branch -M main
git push -u origin main
" ! [rejected] main -> main (non-fast-forward)"
๐ฅ git push ์์ ์์ ์๋ฌ๊ฐ ๋ ์ "git push origin main(๋ธ๋ฐ์น๋ช ) --force " ๋ก ๊ฐ์ ๋ฎ์ด์ฐ๊ธฐ ์คํ
๐ PokéAPI ์ฐ๊ฒฐ
๐น ๊ณต์ API ์ฃผ์ : https://pokeapi.co/api/v2/pokemon
limit๊ณผ offset์ ํตํด ์ํ๋ ์๋๋ง ๋ฐ์์ฌ ์ ์๋ค!
image๋ ๋ฐ๋ก index๋ก ๋ถ๋ฌ์์ผ๋๋ค
// ์ ์ฒด ๋ฆฌ์คํธ
export const fetchPokemonList = async () => {
const res = await fetch("https://pokeapi.co/api/v2/pokemon?limit=20");
return (await res.json()).results;
};
// ์ด๋ฏธ์ง
https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${i + 1}.png
๐ ๋ฆฌ์คํธ ํ๋ฉด ๊ตฌ์ฑ (page.tsx)
// src/app/page.tsx
'use client';
import { useEffect, useState } from 'react';
import PokemonCard from '@/components/PokemonCard';
export default function HomePage() {
const [pokemonList, setPokemonList] = useState([]);
useEffect(() => {
const fetchData = async () => {
const res = await fetch('https://pokeapi.co/api/v2/pokemon?limit=20');
const data = await res.json();
const list = data.results.map((pokemon: any, index: number) => ({
name: pokemon.name,
image: `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${
index + 1
}.png`,
}));
setPokemonList(list);
};
fetchData();
}, []);
return (
<main className="p-6 grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-6">
{pokemonList.map((p) => (
<PokemonCard key={p.name} name={p.name} image={p.image} />
))}
</main>
);
}
fecth ํจ์๋ฅผ ๋ฐ๋ก ์จ์ page๋ฅผ ์๋ฒ๋ ๋๋ง์ผ๋ก ๊ฐ๋ ๋์ง๋ง, pokemon api์ ์ด๋ฏธ์ง๋ฅผ ๋ฐ๋ก ๋ถ๋ฌ์์ผ ๋์ client ์์ ์ฌ์ฉ๊ฐ๋ฅํ useEffect, useState ์ฌ์ฉํ์๋ค.
๐ Vercel ๋ฐฐํฌ๋ ์ค๋น ์๋ฃ (์์ )
๐ GitHub์ ์ฐ๋๋๋ฏ๋ก push๋ง ํด๋ ์๋ ๋ฐฐํฌ ๊ฐ๋ฅ!!
[๐ Vercel ๋ฐฐํฌ ๋งํฌ] – ๋ค์ ํธ์์ ์ฐ๊ฒฐ ์์ !
๐ง ์ค๋์ ํ๊ณ
- Next.js ํ๋ก์ ํธ ์ธํ ์ ์ด์ ์ ๋ฒ ์ต์ํด์ก๋ค
- GitHub ์ฐ๊ฒฐ์ ๊ธฐ๋ณธ ์ค์ ๊ธฐ๋ณธ! ๋ชจ๋ ๊ธฐ๋ก์ ๊น๋ํ๊ฒ ๋จ๊ธฐ๋ ์ต๊ด ๋ค์ด๊ธฐ
๐ ๋ค์ ๋ชฉํ (์๊ณ ํธ)
- ์์ธ ํ์ด์ง ๋ง๋ค๊ธฐ (/pokemon/[name])
- ๊ฐ ํฌ์ผ๋ชฌ์ ๋ฅ๋ ฅ์น, ํ์ ๋ถ๋ฌ์ค๊ธฐ
- ํ์ด์ง ์ด๋ ๊ตฌํ
๐ ์ด์ ๊ธ : [ํฌ์ผ๋ชฌ ๋๊ฐ ํ๋ก์ ํธ] #1 – ์ฌ์ด๋ ํ๋ก์ ํธ ์์! ๊ธฐํ & ๋ชฉํ ์ค์