Skip to content

Conversation

@twtwkim
Copy link
Collaborator

@twtwkim twtwkim commented Jan 10, 2025

요구사항

기본

중고마켓

  • '상품 등록하기' 버튼을 누르면 "/additem" 로 이동합니다.
  • 각 상품 클릭 시 상품 상세 페이지로 이동합니다.
  • 상품 상세 페이지 주소는 "/items/{productId}" 입니다.

상품 상세

  • 내가 등록한 상품일 경우 상품 수정, 삭제가 가능합니다.
  • 문의하기 input창에 값을 입력 후 '등록' 버튼을 누르면 댓글이 등록됩니다.
  • 내가 등록한 댓글은 수정, 삭제가 가능합니다.

상품 등록

  • 이미지를 제외하고 input 에 모든 값을 입력하면 '등록' 버튼이 활성화 됩니다.
  • 활성화된 '등록' 버튼을 누르면 상품 등록이 완료됩니다.
  • 등록이 완료되면 해당 상품 상세 페이지로 이동합니다.

심화

  • api 요청에 TanStack React Query를 활용해 주세요.

주요 변경사항

  • 넥스트로 진행했던 미션 내용을 합쳤습니다. 브랜치도 이상해서 새로 팠더니 파일이 많아졌습니다.....;;; -> PR 다시 올려유
  • 요구사항 외 swagger에서 제공하는 api는 모두 활용해서 기능을 붙였습니다.

스크린샷

배포

멘토에게

  • 리팩토링은 차차 진행하겠습니다.
  • 지난 리뷰는 반영하였습니다.
  • 다만, 지난 리뷰 중 api는 파일별로 분리하는게 좋겠다는 말씀을 해주셨는데, api 개수가 많아져도 함수별로 파일을 따로 만들어서 관리하는게 좋을까요?? 아니면 카테고리 별로 분리하는게 좋을까요???
  • 리액트 쿼리는 처음 사용해봤는데, 조금 더 공부가 필요할 것 같습니다. 제대로 쓴 건지 잘 모르겠네요;;

리뷰 중점사항(전체적으로 손대다보니 변경된 파일이 많았습니다. 자잘한 내용 제외하고 아래와 같이 정리했습니다.)

/components

  • /AddBoard/AddBoard.tsx
  • /AddItemPage/FileInput.tsx -> 조건별 '등록' or '수정' 페이지로 기능하도록 작업
  • /Board/ArticleCommentInfo.tsx -> 댓글 삭제, 수정 기능 작업
  • /Board/ArticleInfo.tsx -> 게시글 좋아요, 취소 & 게시글 수정, 삭제 작업(mutation)
  • /DetailItemPage/Comment.tsx -> 댓글 수정 모드시 ui 다르게 작업(적절한지?)
  • /DetailItemPage/FavoriteCount.tsx -> 상품 좋아요, 취소 & 게시글 수정, 삭제 작업(mutation)
  • /MainPage/AllItem.tsx -> 검색 시 debounce 적용해봤는데 어렵네요..;;

/hooks/useDebounce -> 디바운스 적용하려고 커스텀 훅 하나 만들었습니다.

/redux -> 여러 컴포넌트에서 데이터 활용하기 위한 리덕스 추가

@twtwkim twtwkim requested a review from jyh0521 January 10, 2025 12:27
@twtwkim twtwkim self-assigned this Jan 10, 2025
@twtwkim twtwkim added the 매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다. label Jan 10, 2025
Copy link
Collaborator

@jyh0521 jyh0521 left a comment

Choose a reason for hiding this comment

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

고생하셨습니다 👍

Copy link
Collaborator

Choose a reason for hiding this comment

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

혹시 일부러 개행을 해주신걸까요? package.json은 굳이 개행해주시지 않아도 괜찮습니다.

Copy link
Collaborator

Choose a reason for hiding this comment

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

.env는 .gitignore에 추가해서 깃에 올라오지 않게 해주시는 것이 좋습니다.

Comment on lines +59 to +69
let postData: any = {
title: value.title,
content: value.content,
};

// 이미지가 있을 경우만 imageUrl을 추가
if (image) {
postData.image = await uploadImage(image);
} else if (articleDetail?.image) {
postData.image = articleDetail.image;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

postData의 타입을 any로 지정하고 image url이 있는 경우에만 추가해서 사용하는 것은 타입에 대해 안전하지 않아 보입니다. any 대신 postData의 타입을 잘 설정해서 사용해보시면 좋을 것 같아요.

Comment on lines +72 to +77
await editArticle(postData, articleId);
toast.success("게시글이 수정되었습니다.");
navigate(`/board/${articleId}`);
} else {
// 게시글 등록
const createdPost = await createPost(postData);
Copy link
Collaborator

Choose a reason for hiding this comment

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

edit나 create 함수도 useMutation이라는 함수를 적용해보셔도 좋을 것 같아요~

const FileInput = ({ initialValues = INITIAL_VALUES }) => {
// 이미지와 태그 상태를 별도로 관리
const [preview, setPreview] = useState<string | null>(null);
const [preview, setPreview] = useState<string | null | undefined>(null);
Copy link
Collaborator

Choose a reason for hiding this comment

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

null이 들어간다면 undefiend는 사용하지 않아도 될 것 같아보입니다.

Comment on lines +62 to +68
if (productId) {
// 상품 수정 모드
return editProduct(newProduct, productId); // 상품 수정 API 호출 함수
} else {
// 상품 등록 모드
return postProduct(newProduct); // 상품 등록 API 호출 함수
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

저는 개인적으로 mutation 하나당 하나의 api 요청을 보내는 것을 선호하긴 합니다. 추후에 로직이 길어진다면 분리해보는 것도 고려해보시면 좋을 것 같습니다.

import React, { useState } from "react";
import { FormatDateAgo } from "../../util/FormatDate";
import styles from "./ArticleCommentInfo.module.css";
import dotIcon from "../../assets/images/dotIcon.svg";
Copy link
Collaborator

Choose a reason for hiding this comment

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

alias path도 적용해보시면 좋을 것 같습니다.


const handleEditSave = async (commentId: number, writerId: number) => {
if (writerId !== user.id) {
toast.warning("본인의 댓글만 수정할 수 있습니다.");
Copy link
Collaborator

Choose a reason for hiding this comment

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

toast 라이브러리 활용 잘해주셨네요. 기회가 되면 만들어보시는 것도 추천드립니다.

onSuccess: () => {
toast.success("게시글 좋아요가 완료되었습니다.");
setClickFavorite(true);
setCurrentCount((prev) => prev + 1);
Copy link
Collaborator

Choose a reason for hiding this comment

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

낙관적 업데이트 하는 방법도 한번 알아보시면 좋을 것 같습니다.

Copy link
Collaborator

Choose a reason for hiding this comment

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

useDebounce 훅 잘 만들어주셨네요!

@jyh0521
Copy link
Collaborator

jyh0521 commented Jan 13, 2025

리액트 쿼리 잘 사용해주고 계신 것 같아요~ useMutation도 얼른 적용해보시면 좋을 것 같습니다!

@jyh0521 jyh0521 merged commit 777e25a into codeit-bootcamp-frontend:React-김태완 Jan 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants