본문 바로가기
카테고리 없음

실제 유즈케이스

by 잘먹는 개발자 에단 2025. 6. 24.

1. 

어떤 한 페이지 ( 단일 컴포넌트나 몇개의 컴포넌트 ) 에서 state로 사용할 것은

위에 interface를 정의한다.

 

예를 들어서 이렇게

interface Course {
  id: number;
  title: string;
  description: string;
  status: "completed" | "in-progress" | "not-started" | "required";
  progress: number;
  duration: string;
  dueDate?: string;
}

const CourseLists: React.FC = () => {
  const navigate = useNavigate();
  const [courses, setCourses] = useState<Course[]>(mockCourses);
  const [loading, setLoading] = useState(false);

 

 

2. 

컴포넌트 안에서 param을 다르게 주면 변하는 아이콘을 만드려면

 

  const getStatusIcon = (status: Course["status"]) => {
    switch (status) {
      case "completed":
        return <CheckCircle size={20} color="#10B981" />;
      case "in-progress":
        return <Clock size={20} color="#F59E0B" />;
      case "not-started":
        return <PlayCircle size={20} color="#6B7280" />;
      case "required":
        return <AlertCircle size={20} color="#EF4444" />;
      default:
        return <PlayCircle size={20} color="#6B7280" />;
    }
  };

 

 

 

3.

안에서 api를 편하게 호출하기 위해서 함수로 감싸는 경우

 

api 응답을 통일 시키고, 공통 api 호출함수를 만든다.

interface ApiResponse<T = unknown>{
	success : boolean;
    data? : T;
    message? : string;
    error? : string;
}

const apiCall = async<T>(
	endpoint : string,
    options? : RequestInit
): Promise<ApiResponse<T>> => {
	try{
    	const response = fetch(`${API_BASE_URL}${endpoint}`,{
        	headers : {
            	'Content-Type' : 'application/json',
                ...options?.headers,
            },
            ...options
            
        });
        const data = await response.json();
        return data;
    }catch(error){
    	console.error('API 호출오류입니다', error);
    }
}

 

# RequestInit은 웹 표준 api의 타입이다.

RequestInit에는 다음과 같은 속성들이 포함되어있다. 

----

method: HTTP 메서드 (GET, POST, PUT, DELETE 등)
headers: 요청 헤더들
body: 요청 본문 데이터
mode: CORS 모드 설정
credentials: 쿠키/인증 정보 포함 여부
cache: 캐시 정책
redirect: 리다이렉트 처리 방식
그 외 여러 fetch 옵션들

----

 

 

이렇게 감싸면 API 호출부를 다음과 같이 간소화할 수 있다.

// === 공지사항 관련 API ===
export const announcementApi = {
  // 공지사항 목록 조회
  getAnnouncements: (limit?: number, offset?: number) => {
    const params = new URLSearchParams();
    if (limit) params.append("limit", limit.toString());
    if (offset) params.append("offset", offset.toString());
    return apiCall(`/announcements?${params.toString()}`);
  },

  // 최신 공지사항 조회 (홈페이지용)
  getRecentAnnouncements: () => apiCall("/announcements/recent"),

  // 관리용 공지사항 목록 조회 (비활성화된 것도 포함)
  getManageAnnouncements: (limit?: number, offset?: number) => {
    const params = new URLSearchParams();
    if (limit) params.append("limit", limit.toString());
    if (offset) params.append("offset", offset.toString());
    return apiCall(`/announcements/manage?${params.toString()}`);
  },

  // 특정 공지사항 상세 조회
  getAnnouncementDetail: (announcementId: string | number) =>
    apiCall(`/announcements/${announcementId}`),

  // 공지사항 생성
  createAnnouncement: (announcement: {
    title: string;
    content: string;
    is_active?: boolean;
  }) =>
    apiCall("/announcements", {
      method: "POST",
      body: JSON.stringify(announcement),
    }),

  // 공지사항 수정
  updateAnnouncement: (
    announcementId: string | number,
    announcement: { title: string; content: string; is_active?: boolean }
  ) =>
    apiCall(`/announcements/${announcementId}`, {
      method: "PUT",
      body: JSON.stringify(announcement),
    }),

  // 공지사항 삭제 (소프트 삭제)
  deleteAnnouncement: (announcementId: string | number) =>
    apiCall(`/announcements/${announcementId}`, {
      method: "DELETE",
    }),

  // 공지사항 활성화/비활성화 토글
  toggleAnnouncementStatus: (announcementId: string | number) =>
    apiCall(`/announcements/${announcementId}/toggle`, {
      method: "PATCH",
    }),
};