[DevCamp] ๐Ÿšฆ API ํ†ต์‹  ๋ชจ๋“ˆ ๊ตฌ์„ฑ๊ณผ React ๋ผ์šฐํŒ… ํŒจํ„ด

๋™๊ฑดยท2025๋…„ 4์›” 21์ผ
0

DevCamp

๋ชฉ๋ก ๋ณด๊ธฐ
52/85

๐Ÿšฆ API ํ†ต์‹  ๋ชจ๋“ˆ ๊ตฌ์„ฑ๊ณผ React ๋ผ์šฐํŒ… ํŒจํ„ด

ํ”„๋ก ํŠธ์—”๋“œ์—์„œ API์™€ ํ†ต์‹ ํ•˜๋Š” ์ผ์€ ๋งค์šฐ ํ”ํ•˜์ง€๋งŒ, ์ฝ”๋“œ์˜ ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด ๊ตฌ์กฐํ™”๋œ ํ๋ฆ„์ด ์ค‘์š”ํ•˜๋‹ค. ์˜ค๋Š˜์€ React ํ”„๋กœ์ ํŠธ์—์„œ API ํ†ต์‹ ์„ ์–ด๋–ป๊ฒŒ ๋ชจ๋“ˆํ™”ํ•˜๋ฉด ์ข‹์€์ง€, ๊ทธ๋ฆฌ๊ณ  React์—์„œ ๋ผ์šฐํŒ…์„ ์–ด๋–ป๊ฒŒ ์„ค์ •ํ•˜๋Š”์ง€๋ฅผ ์ •๋ฆฌํ•ด๋ณธ๋‹ค.


๐ŸŒ API ํ†ต์‹  ๋ชจ๋“ˆ ๊ตฌ์„ฑํ•˜๊ธฐ

โœ… API ์š”์ฒญ ํ๋ฆ„

View (Header.tsx)
    โ†“
Hooks (useCategory.ts)
    โ†“
Query Library (์˜ˆ: react-query, tanstack-query) [Optional]
    โ†“
Fetcher (category.api.ts โ†’ http.ts)
    โ†“
API Server

๐Ÿ“ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ ์˜ˆ์‹œ

src/
 โ”œโ”€โ”€ components/
 โ”œโ”€โ”€ hooks/
 โ”‚    โ””โ”€โ”€ useCategory.ts
 โ”œโ”€โ”€ api/
 โ”‚    โ”œโ”€โ”€ category.api.ts
 โ”‚    โ””โ”€โ”€ http.ts
 โ””โ”€โ”€ pages/

๐Ÿ“Œ ๋ชจ๋“ˆ๋ณ„ ์—ญํ•  ์ •๋ฆฌ

  • View (Header.tsx)
    โ†’ UI์—์„œ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๋Š” ์‹œ์ž‘์ . useCategory ๊ฐ™์€ ์ปค์Šคํ…€ ํ›…์„ ํ˜ธ์ถœํ•œ๋‹ค.

  • Hooks (useCategory.ts)
    โ†’ API ํ˜ธ์ถœ ๋กœ์ง์„ ์บก์Аํ™”ํ•˜์—ฌ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค. useEffect, useQuery ๋“ฑ์„ ํ™œ์šฉ.

  • Fetcher (category.api.ts)
    โ†’ ํŠน์ • API์— ๋Œ€ํ•œ ์š”์ฒญ ๋กœ์ง์„ ๋‹ด๋‹นํ•œ๋‹ค. ์š”์ฒญ ๊ฒฝ๋กœ, ํŒŒ๋ผ๋ฏธํ„ฐ, ์‘๋‹ต ํƒ€์ž… ์ง€์ • ๋“ฑ์„ ํฌํ•จ.

  • ๊ณตํ†ต Fetcher (http.ts)
    โ†’ axios ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ๊ธฐ๋ณธ ํ—ค๋” ์„ค์ •, ์ธํ„ฐ์…‰ํ„ฐ ๋“ฑ์„ ์„ค์ •ํ•˜๋Š” ๊ณตํ†ต ๋ชจ๋“ˆ.

๐Ÿงฑ ์ฝ”๋“œ ์˜ˆ์‹œ

// hooks/useCategory.ts
import { useEffect, useState } from "react";
import { getCategory } from "../api/category.api";

export const useCategory = () => {
  const [data, setData] = useState(null);

  useEffect(() => {
    getCategory().then(setData);
  }, []);

  return data;
};
// api/category.api.ts
import { http } from './http';

export const getCategory = () => {
  return http.get('/category');
};
// api/http.ts
import axios from 'axios';

export const http = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  headers: {
    'Content-Type': 'application/json',
  },
});

๐Ÿงญ React ๋ผ์šฐํŒ… ์ž‘์„ฑ ๋ฐฉ๋ฒ•

React Router๋ฅผ ํ†ตํ•ด SPA(single-page application)์—์„œ ํŽ˜์ด์ง€ ์ „ํ™˜์„ ๋งค๋„๋Ÿฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ—‚ ๊ธฐ๋ณธ ๊ตฌ์กฐ

// App.tsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </BrowserRouter>
  );
}

๐Ÿงพ ๋ผ์šฐํŒ… ๊ด€๋ จ ๊ฟ€ํŒ

  • useNavigate()๋กœ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ์ด๋™ ๊ฐ€๋Šฅ
  • ๋™์  ๋ผ์šฐํŒ… (์˜ˆ: /post/:id) ๋„ ์‰ฝ๊ฒŒ ์„ค์ •
  • ์ค‘์ฒฉ ๋ผ์šฐํŠธ(Nested Routes)๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๋ ˆ์ด์•„์›ƒ ๊ณต์œ ๊ฐ€ ์‰ฌ์›€
  • Outlet ์ปดํฌ๋„ŒํŠธ๋กœ ์ž์‹ ๋ผ์šฐํŠธ๋ฅผ ํ‘œ์‹œ

๐Ÿ”จ TIL

  • API ํ†ต์‹ ์€ View โ†’ Hooks โ†’ API module โ†’ Fetcher โ†’ Server ์ˆœ์œผ๋กœ ๊ตฌ์„ฑํ•˜๋ฉด ์ถ”์ ์ด ์‰ฝ๊ณ  ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋†’๋‹ค.
  • axios ์ธ์Šคํ„ด์Šค๋ฅผ ๋”ฐ๋กœ ๋ถ„๋ฆฌํ•˜๋ฉด ํ—ค๋”, ์ธํ„ฐ์…‰ํ„ฐ ์„ค์ •์ด ํ›จ์”ฌ ๊ฐ„ํŽธํ•˜๋‹ค.
  • React ๋ผ์šฐํŒ…์€ BrowserRouter, Routes, Route๋กœ ๊ตฌ์„ฑํ•˜๋ฉฐ, ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ…์ด ๊ฐ€๋Šฅํ•ด ์ง๊ด€์ ์ด๋‹ค.
  • react-router-dom์˜ ๊ธฐ๋Šฅ์„ ์ž˜ ์ดํ•ดํ•˜๊ณ  ํ™œ์šฉํ•˜๋ฉด ๋™์  ๋ผ์šฐํŒ…๊ณผ ์ค‘์ฒฉ ๋ ˆ์ด์•„์›ƒ ๊ตฌ์„ฑ๋„ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
profile
๋ฐฐ๊ณ ํ”ˆ ๊ฐœ๋ฐœ์ž

0๊ฐœ์˜ ๋Œ“๊ธ€