Skip to content

[원치준] sprint8#128

Merged
Irelander merged 5 commits intocodeit-sprint-fullstack:next-원치준from
CHIJUNEE:next-원치준-sprint8
Oct 1, 2025

Hidden character warning

The head ref may contain hidden characters: "next-\uc6d0\uce58\uc900-sprint8"
Merged

[원치준] sprint8#128
Irelander merged 5 commits intocodeit-sprint-fullstack:next-원치준from
CHIJUNEE:next-원치준-sprint8

Conversation

@CHIJUNEE
Copy link
Collaborator

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

스크린샷

image

image

@CHIJUNEE CHIJUNEE marked this pull request as ready for review September 28, 2025 09:55
@CHIJUNEE CHIJUNEE requested a review from Irelander September 28, 2025 09:55
@CHIJUNEE
Copy link
Collaborator 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.

치준님, 전체적으로 코드를 살펴봤는데요. Next.js 고급 패턴들을 완벽하게 활용하고 있어서 이미 실무 수준이에요. 다만 변수명, 오타, 텍스트 같은 디테일 부분만 조금 더 꼼꼼하게 체크하면 완벽할 것 같아요. 코드 작성 후 한 번 더 검토하는 습관만 들이면 바로 실무 투입 가능한 수준이에요. 정말 잘하고 있어요!

아래의 부분들만 조금 더 신경쓰시면 좋을꺼 같아요 !

개선하면 좋을 부분들

  1. 네이밍 체크 - 치준님,,, 생각보다 오타가 많으신거 같더라구요 ?! ㅎㅎㅎ IDE툴들 보면 오타체커 같은게 있어서 실시간으로 오타로 의심되는 부분들 표시되도록 켜둘수도 있어요! 이런거 활용하면 오탈자를 줄일수 있을꺼에요!

  2. 검색/정렬 처리 위치 - 지금은 클라이언트에서 필터링하는데, 데이터가 많아지면 성능 이슈가 있을 수 있어요. 백엔드에서 처리하도록 API 파라미터로 넘기는 게 좋아요.

  3. 페이지네이션 - 현재 모든 데이터를 한 번에 가져오는데, 페이지네이션 추가하면 더 좋을 것 같아요.

  4. 라우팅 - window.location.href 대신 Next.js router 사용하면 전체 새로고침 없이 부드럽게 이동할 수 있어요.

이번 스프린트도 고생 많으셨습니다. :)

Comment on lines +13 to +35
useEffect(() => {
function onDocClick(e) {
if (!open) return;
const t = e.target;
if (
menuRef.current &&
!menuRef.current.contains(t) &&
btnRef.current &&
!btnRef.current.contains(t)
) {
setOpen(false);
}
}
function onKey(e) {
if (e.key === "Escape") setOpen(false);
}
document.addEventListener("mousedown", onDocClick);
document.addEventListener("keydown", onKey);
return () => {
document.removeEventListener("mousedown", onDocClick);
document.removeEventListener("keydown", onKey);
};
}, [open]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

btnRef와 menuRef를 둘 다 체크해서 버튼 클릭은 토글하고, 바깥 클릭만 닫히게 한 게 UX를 고려한 훌륭한 코드예요.
ESC 키 처리 + cleanup 함수도 최고입니다 👏 👏 👏 👏

method: "DELETE",
});
if (!res.ok) throw new Error("삭제 실패");
window.location.href = "/board";
Copy link
Collaborator

Choose a reason for hiding this comment

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

window.location.href는 전체 페이지를 새로고침해요.
Next.js에서는 router.push()나 router.replace()를 쓰는 게 더 좋아요.

import React, { useEffect, useMemo, useState } from "react";

const MarketPage = () => {
const [articles, setarticles] = useState([]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

setarticles (소문자 a)만 JavaScript 네이밍 컨벤션을 따르지 않고 있네요!

const [search, setSearch] = useState("");
const [sortKey, setSortKey] = useState("latest");

const BASE_URL = process.env.NEXT_PUBLIC_API_BASE;
Copy link
Collaborator

Choose a reason for hiding this comment

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

BASE_URL이 undefined일 수 있어요.
사전에 검사해서 오류를 미리 예측하면 좋을꺼 같아요 ! ㅎㅎ

Comment on lines +46 to +60
const visibleList = useMemo(() => {
const q = search.trim().toLowerCase();
const filtered = q
? articles.filter((p) => {
const title = (p?.name ?? p?.title ?? "").toLowerCase();
return title.includes(q);
})
: articles.slice();

filtered.sort((a, b) => {
const ad = new Date(getCreatedAt(a) ?? 0).getTime();
const bd = new Date(getCreatedAt(b) ?? 0).getTime();
if (sortKey === "latest") return bd - ad;
return ad - bd;
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

useMemo 사용은 좋지만, 지금은 괜찮지만 실제 운영환경에서는 검색과 정렬을 프론트에서 하면 안되는점 참고하세요!

만약 프론트에서 처리한다면 다음과 같은 문제점이 생기기 때문이에요.
문제점:

  1. 모든 데이터를 한 번에 가져와야 함 (메모리 낭비)
  2. 데이터가 1000개면? 10000개면? (성능 문제)
  3. 백엔드 DB 인덱스를 활용 못 함

@Irelander Irelander merged commit 25f6870 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.

2 participants