Skip to content

Conversation

@MyungJiwoo
Copy link
Collaborator

판다마켓 6

🌐 배포 url: https://myungjiwoo-pandamarket.netlify.app/additem

기본 요구사항

  • Github의 PR을 만들어서 미션을 제출한다.
  • 피그마 디자인에 맞게 페이지를 만든다.
  • React를 활용해서 구현한다.

체크 리스트 (기본)

  • 상품 등록 페이지 주소는 "/additem"이다.
  • 페이지 주소가 "/additem"일 때 상단 네비게이션바의 "중고마켓" 버튼의 색상은 "3692FF"이다.
  • 상품 이미지는 최대 한 개까지 업로드할 수 있다.
  • 각 input의 placeholder 값을 정확히 입력한다.
  • 이미지를 제외하고 input에 모든 값을 입력하면 '등록' 버튼이 활성화 된다. (api를 통한 상품 등록은 추후 미션에서 적용)

체크 리스트 (심화)

  • 이미지 안의 x 버튼을 누르면 이미지가 삭제된다.
  • 추가된 태그 안의 x 버튼을 누르면 해당 태그는 삭제된다.

추가 기능

  • 오류 메시지를 토스트 메시지로 구현 (react-toastify 라이브러리 사용)

구현 포인트

  • 입력 컴포넌트 계층화 및 재사용
    • Base~ 컴포넌트 : 최소 단위 입력 컴포넌트
    • ~Field 컴포넌트 : 공통 인터페이스를 추가한 확장 컴포넌트 (label, error messge 등)
    • Item~Field 컴포넌트 : 도메인 전용 컴포넌트

스크린샷

기능 스크린샷
상품 등록 sprint6-상품등록
이미지, 태그 삭제 sprint6-이미지랑 태그 삭제

멘토에게

MyungJiwoo added 26 commits May 8, 2025 21:17
@MyungJiwoo MyungJiwoo self-assigned this May 10, 2025
@MyungJiwoo MyungJiwoo added the 매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다. label May 10, 2025
Copy link
Collaborator

@GANGYIKIM GANGYIKIM left a comment

Choose a reason for hiding this comment

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

지우님 6번째 미션 제출 고생하셨습니다.
여러모로 구조에 대해 고민하신 것들이 느껴졌습니다.
협업을 하시면서 많이 배우신 것 같아 즐겁게 리뷰했습니다.
다음 미션도 화이팅이에요.


  • 그전에 코멘트를 확인하시기 전에 작업하셨을 거라고 생각해요. 그 전 미션에서 드렸던 사항은 중복으로 달지 않았으니 참고해주세요~

Comment on lines +1 to +9
const BaseForm = ({ children, onSubmit, ...props }) => {
return (
<form onSubmit={onSubmit} {...props}>
{children}
</form>
);
};

export default BaseForm;
Copy link
Collaborator

Choose a reason for hiding this comment

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

❓ 질문
이렇게 form을 공통 컴포넌트로 빼야하는 이유가 있을까요?
단순히 form의 이름을 바꾸는 느낌이라 그냥 사용해도 될 것 같아요~
만약 의도가 있으시거나 추후 기능을 추가하실 생각이면 두셔도 좋습니다~

@@ -0,0 +1,11 @@
import styled from "@emotion/styled";

const BaseImageInput = ({ type = "file", onChange, ...props }) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

💊 제안
BaseInput이라는 이름은 꼭 다른 image input이 있을것처럼 느껴지게 되네요. 다른 input이 없다면 그냥 ImageInput이여도 될 것 같아요!

import styled from "@emotion/styled";

const BaseImageInput = ({ type = "file", onChange, ...props }) => {
return <Input type={type} accept="image/*" onChange={onChange} {...props} />;
Copy link
Collaborator

Choose a reason for hiding this comment

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

💊 제안
input의 accept 속성은 유저가 어떤 파일을 올려야하는지에 대한 힌트를 제공하는 속성입니다.
유저는 파일 업로드시 accept의 명시된 확장자 이외의 파일도 올릴 수 있으므로
실제 upload 함수에서 한번더 확장자를 검사해주시는 것이 좋습니다.

(사용자가 업로드창에서 옵션을 열어 확장자를 바꾸면 아래처럼 보입니다)
스크린샷 2025-05-08 오후 5 53 17

https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/accept

width: 100%;
height: auto;
min-height: 8rem;
resize: none;
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍 칭찬
resize 막아두신 점 좋아요~


const DeleteButton = ({ onClick, size = "s" }) => {
return (
<DeleteButtonWrapper onClick={onClick} size={BUTTON_SIZE[size]}>
Copy link
Collaborator

Choose a reason for hiding this comment

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

❗️ 수정요청
이런 클릭 가능한 요소의 경우 버튼을 사용해주세요. 더 적절한 태그가 있는데 div 태그에 onClick 을 주게되면 button에게 기대하는 동작을 제대로 수행하지 못합니다!

Suggested change
<DeleteButtonWrapper onClick={onClick} size={BUTTON_SIZE[size]}>
<DeleteButtonWrapper type="button" onClick={onClick} size={BUTTON_SIZE[size]}>

버튼으로 바꿔주시고 type을 명시하시는 것을 추천드려요~

Comment on lines +16 to +21
const [btnAvailable, setBtnAvailable] = useState(false);
const [itemImage, setItemImage] = useState(null);
const [itemName, setItemName] = useState("");
const [itemDescription, setItemDescription] = useState("");
const [itemPrice, setItemPrice] = useState("");
const [tag, setTag] = useState("");
Copy link
Collaborator

Choose a reason for hiding this comment

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

💊 제안
저는 관련있는 것들을 잘 모아두는 것이 가독성을 높여준다고 생각합니다. 지금의 경우 아이템을 생성하는 폼과 관련된 state 들을 각각의 useState로 관리하고 있습니다.
이런 경우 formValue 와 같은 하나의 state로 관리하시거나, useReducer를 이용해보시면 더 가독성 좋게 코드를 작성하실 수 있습니다.

https://ko.react.dev/learn/choosing-the-state-structure
https://ko.react.dev/learn/extracting-state-logic-into-a-reducer

이는 알고만 계시다가 추후 typescript 적용하실때 다시 생각해보시면 도움이 되실 것 같아요.

import { memo } from "react";
import ImageInputField from "@components/ImageInputField";

const ItemNameInputField = ({ imageUrl, onChange, onDelete }) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

❗️ 수정요청
해당 컴포넌트 명은 ItemImageInputField가 더 적절할 것 같아요.

Comment on lines +9 to +11
if (itemTags.has(tagValue)) {
toast(TAG_ALREADY_EXISTS_MESSAGE);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍 칭찬
중복 태그 막으시고 유저에게 피드백 주시는 것 좋아요~


export const useSubmitHandler = (formState) => {
const preventSubmitOnEnter = useCallback((e) => {
// enter로 폼 제출 방지 (태그 생성시 enter로 구분하기 때문이다. 단 textarea에서는 줄바꿈을 허용한다.)
Copy link
Collaborator

Choose a reason for hiding this comment

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

💊 제안
form으로 인풋을 감싸게 되면 내부적으로 enter 키 입력시 submit 이벤트를 실행하게 됩니다. 이때 submit 버튼이 disabled 상태이면 제출 이벤트가 발생하지 않으므로 해당 폼 내부에서 버튼들에게 type을 잘 명시해주셨고 제출이 불가능한 상황에서 submit 버튼을 비활성화 해두셨다면 이는 불필요합니다~

Copy link
Collaborator

Choose a reason for hiding this comment

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

💊 제안
금액관련 인풋에 ,를 넣어 주신 것 좋습니다. 다만 지금의 경우 값이 입력되며 실시간으로 formatting을 수행하며 이에 따라 인풋이 입력될 당시의 커서 위치가 아니라 맨 뒤로 이동이 됩니다.
이런 경우 커서위치를 formatting 후 옮겨주시거나 판매가격 인풋에 포커스 시 다시 number 형태로 formatting하고 포커스가 떠나면 다시 금액 형태로 formatting 하는 방식으로 해주시면서 커서 위치를 유지시켜주셔야합니다~

@GANGYIKIM GANGYIKIM merged commit 626ff03 into codeit-bootcamp-frontend:React-명지우 May 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.

2 participants