Skip to content

[곽민준] sprint8#127

Merged
Irelander merged 4 commits intocodeit-sprint-fullstack:next-곽민준from
kmjerror:next-곽민준-sprint8
Oct 1, 2025

Hidden character warning

The head ref may contain hidden characters: "next-\uacfd\ubbfc\uc900-sprint8"
Merged

[곽민준] sprint8#127
Irelander merged 4 commits intocodeit-sprint-fullstack:next-곽민준from
kmjerror:next-곽민준-sprint8

Conversation

@kmjerror
Copy link

@kmjerror kmjerror commented Sep 23, 2025

요구사항

기본 요구사항

공통

  • 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로 마이그레이션 해주세요.
  • 마이그레이션에 상당한 시간이 소요될 수 있으므로 진행을 권장하지 않습니다.

Screenshot 2025-09-26 at 18 19 10

Screenshot 2025-09-26 at 18 19 23

Screenshot 2025-09-26 at 18 19 34

Screenshot 2025-09-26 at 18 19 57

keepoki and others added 2 commits September 17, 2025 16:20
…준-sprint6-clean2

[곽민준] sprint 6 다음엔 충돌 잘 해결해보아요~
@kmjerror
Copy link
Author

Copy link
Collaborator

@Irelander Irelander left a comment

Choose a reason for hiding this comment

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

전반적으로 고급 기법들을 잘 활용하고 있어서 인상 깊었어요.

특히 Optimistic Update로 댓글 추가 시 즉시 UI에 반영하고 실패 시 롤백하는 패턴, cleanup 함수로 메모리 누수를 방지하는 부분, Promise.all로 병렬 요청 처리하는 성능 최적화, 그리고 API 레이어를 깔끔하게 분리한 점이 정말 훌륭했습니다. 공통 fetch 함수로 중복 코드를 제거한 것도 좋았고요.

다만 몇 가지 개선이 필요한 부분이 있어요. 고정 px 값 대신 Tailwind 반응형 클래스를 사용해서 모바일 대응이 되면 더 좋을꺼 같아요. 정렬 옵션에 좋아요순을 추가하고, API 호출 시 try-catch로 에러 처리를 강화하며, 검색 기능에 버튼을 추가하거나 디바운싱을 적용하면 사용자 경험이 더 좋아질 거예요. !

정말 잘하고 있어요, 화이팅!

Comment on lines +6 to +11
const decorate = (post) => ({
imageUrl: DEFAULT_IMAGE_URL,
nickname: post.nickname ?? "user_0000",
likes: typeof post.likes === "number" ? post.likes : 0,
...post,
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

decorate 함수 접근 좋은데요 ?

다만 현재코드는 imageUrl을 무조건 DEFAULT_IMAGE_URL로 덮어쓰게 되어 있어요.
백엔드에서 실제 이미지 URL이 와도 무시가 되니 아래처럼 변경하면 더 좋을꺼 같습니다 !

imageUrl: post.imageUrl || post.image || DEFAULT_IMAGE_URL,

전체적으로 방어적 프로그래밍 사고는 정말 좋아요!

Comment on lines +13 to +17
async function json(url, init) {
const res = await fetch(url, { cache: "no-store", headers: { "Content-Type": "application/json" }, ...init });
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
return res.json();
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

에러가 좀더 상세히 핸들링 되면 ( 세부 응답 코드 ) 좋을꺼 같고 추가로 에러 로깅이 추가 되면 좋을꺼 같아요!

Comment on lines +17 to +44
async function load() {
try {
setErr("");
setLoading(true);

const [listRes, bestRes] = await Promise.all([
getPosts({ page: 1, limit: 4, sort, keyword }),
getBestPosts(),
]);

const listItems = Array.isArray(listRes) ? listRes : (listRes?.items ?? listRes?.data ?? []);
const bestItems = Array.isArray(bestRes) ? bestRes : (bestRes?.items ?? bestRes?.data ?? []);

setPosts(listItems.slice(0, 4));
setBest(bestItems.slice(0, 3));
} catch {
setErr("목록을 불러오지 못했습니다.");
} finally {
setLoading(false);
}
}

useEffect(() => { load(); }, [sort]);

const onSearch = (e) => {
e.preventDefault();
load();
};
Copy link
Collaborator

Choose a reason for hiding this comment

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

onSearch에서는 수동으로 load를 호출하고 있어서 일관성이 떨어지는거 같아요!

  • sort가 바뀌면 → useEffectload() 호출
  • keyword가 바뀌면 → 수동으로 load() 호출

useCallback과 debounce를 조합해서 useEffect에 keyword를 넣어서 처리하면 더 좋을꺼 같습니다

Comment on lines +30 to +31
setPosts(listItems.slice(0, 4));
setBest(bestItems.slice(0, 3));
Copy link
Collaborator

Choose a reason for hiding this comment

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

상수 분리: 매직넘버들을 파일 상단에 상수로 빼면 유지보수가 쉬워져요

const INITIAL_PAGE_SIZE = 4;
const BEST_POSTS_LIMIT = 3;

@Irelander Irelander merged commit b2a94f0 into codeit-sprint-fullstack:next-곽민준 Oct 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants