Skip to content

feat: 새 글 작성을 위한 화면 조회(카테고리, 태그 조회) API 연동#116

Merged
ljh130334 merged 2 commits into
developfrom
feat/api-feeds-check
Aug 14, 2025
Merged

feat: 새 글 작성을 위한 화면 조회(카테고리, 태그 조회) API 연동#116
ljh130334 merged 2 commits into
developfrom
feat/api-feeds-check

Conversation

@ljh130334
Copy link
Copy Markdown
Member

@ljh130334 ljh130334 commented Aug 14, 2025

#️⃣ 연관된 이슈

#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

  • 새로운 기능

    • 게시글 작성의 태그 선택이 서버에서 최신 카테고리·태그를 동적으로 불러오도록 개선되었습니다.
    • 데이터 로딩 중 상태 표시(“로딩 중...”)가 추가되었습니다.
    • 카테고리 버튼으로 손쉽게 전환하며, 선택된 카테고리에 맞춘 태그 목록이 표시됩니다.
    • 태그 선택 제한(최대 5개)이 유지됩니다.
  • 리팩터링

    • 하드코딩된 장르/태그 정보를 제거하고 데이터 기반 흐름으로 전환했습니다.
    • 로딩·오류 상태 관리와 로깅을 정비해 안정성을 향상했습니다.

@ljh130334 ljh130334 added the 📬 API 서버 API 통신 label Aug 14, 2025
@vercel
Copy link
Copy Markdown

vercel Bot commented Aug 14, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Project Deployment Preview Comments Updated (UTC)
thip Ready Preview Comment Aug 14, 2025 2:58am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Aug 14, 2025

Walkthrough

새 API 모듈을 추가해 글쓰기용 카테고리/태그 정보를 조회하고, 생성 화면의 태그 선택 섹션이 이 API로부터 동적 데이터를 로드하도록 로직을 전환했습니다. 컴포넌트는 마운트 시 데이터 fetch, 로딩 상태 표시, 에러 로깅을 수행하며 선택된 카테고리에 따라 태그를 렌더링합니다.

Changes

Cohort / File(s) Change Summary
API: Write Info 조회 추가
src/api/feeds/getWriteInfo.ts
신규 모듈 추가. 인터페이스 CategoryData, WriteInfoData, GetWriteInfoResponse 정의. getWriteInfo() 구현: apiClient.get('/feeds/write-info') 호출 후 response.data 반환. 내부 에러 처리 없음.
UI: 태그 선택 섹션 동적화
src/components/createpost/TagSelectionSection.tsx
하드코딩된 장르/태그 맵 제거. getWriteInfo로 카테고리/태그 로드. 상태(categories, selectedCategory, loading) 및 useEffect 추가. 로딩 UI 표시, 에러 로깅. 카테고리 버튼과 태그 렌더링을 API 데이터 기반으로 갱신.

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 렌더링
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15–20 minutes

Poem

초원에 깃든 토끼의 코딩 노트
새 태그 향 맡고, 카테고리 쏙!
하드코딩 굴렀던 발자국 지우고
API 길 따라 폴짝폴짝 뛰네
로딩 구름 걷히면, 다섯 잎 태그 꽃 🌸🐇

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 Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/api-feeds-check

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4edb17a and 634b041.

📒 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: 카테고리 변경 시 기존 선택 태그 유지 정책 확인 필요

현재는 카테고리를 바꿔도 기존 선택 태그가 유지됩니다. 요구사항이 “카테고리 간 태그 혼합 허용”인지 “선택 카테고리 내 태그만 허용”인지 확인 부탁드립니다. 후자라면 카테고리 변경 시 선택 태그 초기화가 필요합니다.

@ljh130334 ljh130334 merged commit 9f2ace7 into develop Aug 14, 2025
3 checks passed
@ljh130334 ljh130334 deleted the feat/api-feeds-check branch August 19, 2025 01:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📬 API 서버 API 통신

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant