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",
}),
};