feat: 새 글 작성을 위한 화면 조회(카테고리, 태그 조회) API 연동#116
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
Walkthrough새 API 모듈을 추가해 글쓰기용 카테고리/태그 정보를 조회하고, 생성 화면의 태그 선택 섹션이 이 API로부터 동적 데이터를 로드하도록 로직을 전환했습니다. 컴포넌트는 마운트 시 데이터 fetch, 로딩 상태 표시, 에러 로깅을 수행하며 선택된 카테고리에 따라 태그를 렌더링합니다. Changes
Sequence Diagram(s)sequenceDiagram
participant U as User
participant T as TagSelectionSection
participant A as getWriteInfo (api)
participant C as apiClient
participant S as Server
U->>T: 페이지 진입
T->>A: getWriteInfo()
A->>C: GET /feeds/write-info
C->>S: 요청 전송
S-->>C: 200 OK + {categoryList, ...}
C-->>A: 응답 데이터
A-->>T: GetWriteInfoResponse.data
T->>T: 상태 업데이트 (categories, selectedCategory, loading=false)
U->>T: 카테고리 선택
T->>T: selectedCategory 변경, 해당 tagList 렌더링
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~15–20 minutes Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (8)
src/api/feeds/getWriteInfo.ts (3)
15-20: API 응답 래퍼를 제너릭으로 추출해 재사용성 향상동일한 형태의 표준 응답을 여러 API에서 사용할 가능성이 높아 보입니다. 공용 제너릭 래퍼를 도입하면 타입 중복을 줄이고 일관성을 높일 수 있습니다.
아래처럼 응답 래퍼를 일반화하는 것을 제안드립니다:
-export interface GetWriteInfoResponse { - isSuccess: boolean; - code: number; - message: string; - data: WriteInfoData; -} +export interface ApiResponse<T> { + isSuccess: boolean; + code: number; + message: string; + data: T; +} + +export type GetWriteInfoResponse = ApiResponse<WriteInfoData>;
23-26: 반환 타입 명시와 간단 JSDoc으로 의도 명확화암시적 추론도 맞지만, 명시적으로 반환 타입을 부여하면 사용처에서 의도가 더 분명해집니다. 간단한 JSDoc도 추후 유지보수에 도움이 됩니다.
-// 새 글 작성을 위한 카테고리 및 태그 조회 API 함수 -export const getWriteInfo = async () => { +// 새 글 작성을 위한 카테고리 및 태그 조회 API 함수 +/** + * /feeds/write-info 데이터를 가져옵니다. + * @returns 서버 표준 응답(GetWriteInfoResponse) + */ +export const getWriteInfo = async (): Promise<GetWriteInfoResponse> => { const response = await apiClient.get<GetWriteInfoResponse>('/feeds/write-info'); return response.data; };
1-1: 모듈 경로 스타일 일관화(상대 경로 → path alias 고려)동일 PR 내에서 이 모듈을 불러오는 쪽은 path alias('@')를 사용하고 있습니다(Line 16 in TagSelectionSection.tsx). 내부에서도 alias를 사용하면 경로 이동에 덜 취약하고 일관성이 좋아집니다. 빌드/TS 설정에 따라 적용 가능합니다.
아래 변경을 고려해 주세요(프로젝트의 tsconfig paths가 '@' → 'src'로 설정되어 있다는 전제):
-import { apiClient } from '../index'; +import { apiClient } from '@/api';설정이 다르다면 그대로 두셔도 무방합니다.
src/components/createpost/TagSelectionSection.tsx (5)
28-49: 언마운트 후 setState 경고 방지(취소 플래그) 제안비동기 처리 중 컴포넌트가 언마운트되면 setState 호출로 경고가 발생할 수 있습니다. 간단한 취소 플래그로 이를 방지할 수 있습니다.
아래처럼 가드 코드를 추가해 주세요:
// API에서 카테고리 및 태그 데이터 로드 useEffect(() => { + let cancelled = false; const loadWriteInfo = async () => { try { - setLoading(true); + if (!cancelled) setLoading(true); const response = await getWriteInfo(); - if (response.isSuccess && response.data.categoryList.length > 0) { - setCategories(response.data.categoryList); - // 첫 번째 카테고리를 기본 선택 - setSelectedCategory(response.data.categoryList[0].category); - } + if (!cancelled && response.isSuccess && response.data.categoryList.length > 0) { + setCategories(response.data.categoryList); + // 첫 번째 카테고리를 기본 선택 + setSelectedCategory(response.data.categoryList[0].category); + } } catch (error) { console.error('카테고리 정보 로드 실패:', error); } finally { - setLoading(false); + if (!cancelled) setLoading(false); } }; loadWriteInfo(); + return () => { + cancelled = true; + }; }, []);
71-73: currentTags 계산은 useMemo로 캐싱해 불필요한 연산 감소렌더링마다 find를 수행하는 대신 메모이제이션하면 성능과 의도를 모두 개선할 수 있습니다.
다음 변경을 적용해 주세요. Line 1의 import도 함께 수정됩니다.
- // 현재 선택된 카테고리의 태그 목록 - const currentTags = categories.find(cat => cat.category === selectedCategory)?.tagList || []; + // 현재 선택된 카테고리의 태그 목록 + const currentTags = useMemo( + () => categories.find(cat => cat.category === selectedCategory)?.tagList ?? [], + [categories, selectedCategory], + );추가로 Line 1도 함께 수정:
-import { useState, useEffect } from 'react'; +import { useState, useEffect, useMemo } from 'react';
74-83: 로딩 상태의 접근성 개선(ARIA 속성 추가)보조기기 사용자에게 상태 변화를 알리기 위해 role/aria-live 속성을 추가하는 것을 권장합니다.
- <div>로딩 중...</div> + <div role="status" aria-live="polite">로딩 중...</div>
90-97: 카테고리 토글 버튼에 aria-pressed 추가선택 상태를 스크린리더에 전달하기 위해 토글 버튼에 aria-pressed를 제공하세요.
{categories.map(categoryData => ( <GenreButton key={categoryData.category} active={selectedCategory === categoryData.category} + aria-pressed={selectedCategory === categoryData.category} onClick={() => handleCategorySelect(categoryData.category)} > {categoryData.category} </GenreButton> ))}
102-111: 태그 토글 버튼도 aria-pressed로 접근성 강화태그 선택 여부를 보조기기에 전달합니다.
{currentTags.map(tag => ( <SubTagButton key={tag} active={selectedTags.includes(tag)} + aria-pressed={selectedTags.includes(tag)} disabled={!selectedTags.includes(tag) && selectedTags.length >= 5} onClick={() => handleTagToggle(tag)} > {tag} </SubTagButton> ))}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/api/feeds/getWriteInfo.ts(1 hunks)src/components/createpost/TagSelectionSection.tsx(3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/api/feeds/getWriteInfo.ts (1)
src/api/index.ts (1)
apiClient(7-14)
src/components/createpost/TagSelectionSection.tsx (2)
src/api/feeds/getWriteInfo.ts (2)
CategoryData(4-7)getWriteInfo(23-26)src/components/createpost/TagSelectionSection.styled.ts (4)
TagContainer(4-8)GenreButtonGroup(10-14)GenreButton(16-32)SubTagGrid(34-38)
🔇 Additional comments (4)
src/api/feeds/getWriteInfo.ts (1)
4-12: 타입 모델링 적절합니다카테고리/태그 구조가 단순하고 명확하게 정의되어 있어 이후 컴포넌트 사용처에서도 읽기 좋습니다.
src/components/createpost/TagSelectionSection.tsx (3)
23-27: 상태 분리 및 초기값 설정 좋습니다categories/selectedCategory/loading으로 역할이 명확히 나뉘어 가독성이 좋습니다.
92-92: 키로 카테고리 명 사용 시 고유성 보장 확인 필요카테고리명이 중복될 가능성이 있다면 React key 충돌 및 렌더링 비정상 가능성이 있습니다. 백엔드 응답에 categoryId 같은 고유 식별자가 제공되는지 확인 부탁드립니다. 제공된다면 key를 식별자 기반으로 전환하는 것을 권장합니다.
50-52: 카테고리 변경 시 기존 선택 태그 유지 정책 확인 필요현재는 카테고리를 바꿔도 기존 선택 태그가 유지됩니다. 요구사항이 “카테고리 간 태그 혼합 허용”인지 “선택 카테고리 내 태그만 허용”인지 확인 부탁드립니다. 후자라면 카테고리 변경 시 선택 태그 초기화가 필요합니다.
#️⃣ 연관된 이슈
#71
📝 작업 내용
새 글 작성 시 필요한 카테고리 및 태그 정보를 서버에서 동적으로 가져오도록 API 연동 작업을 수행했습니다.
🕸️ 주요 변경 사항
1. API 연동 파일 신규 생성
src/api/feeds/getWriteInfo.ts파일을 새로 생성하여/feeds/write-info엔드포인트와 연동했습니다. 이 API는 새 글 작성 시 사용할 수 있는 모든 카테고리와 각 카테고리별 태그 목록을 반환합니다.2. TagSelectionSection 컴포넌트 리팩토링
기존에 하드코딩되어 있던 카테고리 및 태그 데이터를 제거하고, 새로 생성한 API를 통해 동적으로 데이터를 로드하도록 변경했습니다. 이를 통해 서버에서 관리하는 최신 카테고리 및 태그 정보를 실시간으로 반영할 수 있게 되었습니다. 컴포넌트 마운트 시 자동으로 API를 호출하여 데이터를 가져오며, 로딩 상태와 에러 처리도 추가했습니다.
3. 데이터 구조 개선
API 응답 구조에 맞춰
CategoryData인터페이스를 정의하고, 각 카테고리별로 태그 목록을 관리하는 구조로 개선했습니다. 기존의 하드코딩된 장르-태그 매핑 구조에서 서버 데이터 기반의 유연한 구조로 변경되어, 향후 카테고리나 태그가 추가/변경될 때 코드 수정 없이 자동으로 반영됩니다.4. 사용자 경험 개선
API 호출 중에는 "로딩 중..." 메시지를 표시하여 사용자에게 상태를 명확히 전달하도록 했습니다. 또한 API 응답의 첫 번째 카테고리를 기본 선택하여 사용자가 별도 조작 없이도 바로 태그를 선택할 수 있도록 했습니다.
Summary by CodeRabbit
새로운 기능
리팩터링