Skip to content

sprint7 조한준#83

Open
BackNo23 wants to merge 1 commit intocodeit-sprint-fullstack:next-조한준from
BackNo23:next-sprint7-조한준

Hidden character warning

The head ref may contain hidden characters: "next-sprint7-\uc870\ud55c\uc900"
Open

sprint7 조한준#83
BackNo23 wants to merge 1 commit intocodeit-sprint-fullstack:next-조한준from
BackNo23:next-sprint7-조한준

Conversation

@BackNo23
Copy link
Collaborator

1. 스프린트 미션 요구사항

기본 요구사항

공통

  • Github에 스프린트 미션 PR을 만들어 주세요.
  • Next.js를 사용해 진행합니다.

자유 게시판 페이지

  • 게시글 목록에서 드롭다운을 사용하여 "최신 순"으로 정렬할 수 있도록 합니다.
  • 본인이 이전 미션에서 생성한 게시글 목록 조회 API를 활용해 GET 메서드로 데이터를 가져옵니다.
  • 게시글 제목에 검색어가 일부 포함되면 해당 게시글을 검색할 수 있도록 합니다.
  • 이미지는 디폴트 이미지로 프론트엔드에서 처리해 주세요.
  • 게시글 노출범위 및 좋아요 개수 역시 임의값으로 프론트엔드에서 처리해주세요.
  • 베스트 게시글은 최신순 3개 게시글을 요청으로 데이터를 가져와 구현해주세요.
  • 자유게시판 페이지에서 특정 게시글을 클릭하면 해당 게시글의 상세 페이지로 이동합니다.

게시글 등록 & 수정 페이지

  • 각 input 필드에 정확한 placeholder 값을 입력합니다.
  • 모든 input 필드에 값을 입력하면 "등록" 버튼이 활성화됩니다.
  • 본인이 이전 미션에서 생성한 게시글 생성 API를 활용해 POST 메서드로 게시글을 등록합니다.
  • "등록" 버튼을 누르면 해당 게시물 상세 페이지로 이동합니다.
  • [] 게시글 수정 페이지 UI는 게시글 등록 페이지와 동일합니다.
  • [] 본인이 이전 미션에서 생성한 게시글 상세 API의 PATCH 메서드를 사용하여 게시물을 수정합니다.

게시글 상세 페이지

  • 본인이 이전 미션에서 생성한 게시글 상세 API의 GET 메서드를 사용하여 데이터를 가져옵니다.
  • 본인이 이전 미션에서 생성한 게시글 상세 API의 DELETE 메서드를 사용하여 게시물을 삭제합니다.
  • 댓글 input에 값을 입력하면 "등록" 버튼이 활성화됩니다.
  • 본인이 이전 미션에서 생성한 댓글 생성 API를 활용해 POST 메서드로 댓글을 등록합니다.
  • [] 본인이 이전 미션에서 생성한 댓글 생성 API를 활용해 PATCH 메서드로 댓글을 수정합니다.
  • [] 본인이 이전 미션에서 생성한 댓글 생성 API를 활용해 DELETE 메서드로 댓글을 삭제합니다.

심화 요구사항

공통

  • [] 디자인 시안에 따라 반응형 디자인을 구현합니다.
  • [] (생략가능)지금까지 진행한 모든 React 코드를 Next.js로 마이그레이션 해주세요.

3. 멘토님에게 남길 메시지

  1. 폴더 구조 관련

현재 폴더 구조가 이렇게 되어 있는데 괜찮은 방식인지 여쭤보고 싶습니다.

src/
└─ app/
   └─ freeboard/
      └─ [id]/
         └─ page.js
└─ components/
   ├─ ArticleDetail/
   │  └─ ArticleDetail.jsx
   ├─ Comments/
   │  └─ Comments.jsx
   ├─ CommentsList/
   │  ├─ CommnetsList.jsx
   │  └─ CommentsListItem/
   │     └─ CommentsListItem.jsx
   └─ ArticleList/
      └─ ArticleCard/
└─ lib/
   ├─ api.js
   └─ actions.js

특정 페이지에서만 사용하는 컴포넌트도 components/ 폴더에 두는 게 맞는지, 아니면 app/freeboard/[id]/ 하위에 두는 게 나은지 궁금합니다.

  1. 서버/클라이언트 컴포넌트 구분 방식 관련

현재 이런 구조로 사용하고 있습니다.

FreeboardDetailPage (서버) → ArticleDetail (서버), Comments (클라이언트), CommnetsList (서버)
api.js의 fetch는 서버 컴포넌트에서만 직접 호출
댓글 등록 후 router.refresh()로 CommnetsList 서버 컴포넌트를 재실행해서 목록을 업데이트
이 방식이 Next.js App Router에서 권장하는 패턴인지 궁금합니다.

  1. Server Action 사용 방식 관련

클라이언트 컴포넌트에서 POST 요청이 필요할 때 두 가지 방법이 있는 것 같아서 어떤 방식이 더 올바른지 여쭤보고 싶습니다.

방법 1. actions.js에 'use server'를 선언해서 Server Action으로 처리
→ 서버에서 실행되므로 API_BASE_URL 환경변수를 NEXT_PUBLIC_ 없이 그대로 사용 가능

방법 2. 환경변수를 NEXT_PUBLIC_API_BASE_URL로 변경해서 클라이언트에서 직접 fetch 호출

현재는 방법 1을 사용하고 있는데, Next.js App Router에서 어떤 방식이 더 권장되는지, 그리고 각각의 장단점이 무엇인지 궁금합니다.

// actions.js
'use server';
export async function submitCreateCommnets(content, articleId) {
return createCommnets(content, articleId);
}
이 방식이 올바른 Server Action 활용인지, 아니면 더 적절한 방법이 있는지 궁금합니다.

@BackNo23 BackNo23 requested a review from wseungjin February 25, 2026 03:06
@BackNo23 BackNo23 self-assigned this Feb 25, 2026
@BackNo23 BackNo23 added 매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다. 최종제출 스프린트 미션 최종 제출 PR입니다. 코드리뷰 및 평가해주세요! labels Feb 25, 2026
Copy link
Collaborator

@wseungjin wseungjin left a comment

Choose a reason for hiding this comment

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

수고하셨습니다.

  1. 폴더 구조 관련

특정 페이지에서만 사용하는 컴포넌트도 components/ 폴더에 두는 편이 더 좋을거 같아요.
app router에는 page 같이 관리하는게 좋을거 같고

좀 더 사이즈가 커진다면

components/특정페이지명
같이 확장도 가능하겠죠.

  1. 서버/클라이언트 컴포넌트 구분 방식 관련

app router를 그렇게 지금 사용하고 있지는 않아서 정확하게는 모르겠는데 충분히 괜찮아 보입니다.
이슈는 없어보이고요.

  1. Server Action 사용 방식 관련

방법 1번이 보안이나 데이터 일관성이나 더 좋아 보입니다.

sort,
}) {
const [items, setItems] = useState(initialItems);
const [page, setPage] = useState(1);
Copy link
Collaborator

Choose a reason for hiding this comment

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

page말고 index 써주시고 0부터 해주시면 더 좋을거 같아요

keyword,
sort,
}) {
const [items, setItems] = useState(initialItems);
Copy link
Collaborator

Choose a reason for hiding this comment

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

관련해서 훅으로 정리하면 어떨까요

loading, error같은 상태를 중간에 두면 더 좋을거 같아요.

const [keyword, setKeyword] = useState(searchParams.get('keyword') ?? '');
const sort = searchParams.get('sort') ?? 'recent';

const buildQuery = (kw, s) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

약자를 좀 지양해주세요

@@ -0,0 +1,59 @@
const BASE_URL = process.env.API_BASE_URL;

export async function getArticles() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

size 넣어서 요청하고 slice로도 끊으면 좋을거 같아요

limit: String(limit),
});
const res = await fetch(`${BASE_URL}/article?${params}`);
if (!res.ok) throw new Error('게시글을 불러오지 못했습니다.');
Copy link
Collaborator

Choose a reason for hiding this comment

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

실패해서 에러 던지면 서버에서 html을 send해줄 수 있나요?
예외처리가 필요하지 않을까요?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다. 최종제출 스프린트 미션 최종 제출 PR입니다. 코드리뷰 및 평가해주세요!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants