Skip to content

Conversation

@minimo-9
Copy link
Collaborator

📌 변경 사항 개요

이미지 업로드 컴포넌트 구현

📝 상세 내용

가게 등록 페이지에 이미지를 등록할 수 있는 인풋 컴포넌트를 구현했습니다.

🔗 관련 이슈

🖼️ 스크린샷(선택사항)

image
image
image
image

💡 참고 사항

@minimo-9 minimo-9 requested review from a user, Moon-ju-young and Yun-Jinwoo June 17, 2025 07:54
@minimo-9 minimo-9 self-assigned this Jun 17, 2025
@minimo-9 minimo-9 added ✨ 기능 추가/구현 새로운 기능을 추가하거나 구현했어요! 🎨 UI/스타일 관련 스타일을 추가하거나 변경했어요! labels Jun 17, 2025
@minimo-9 minimo-9 linked an issue Jun 17, 2025 that may be closed by this pull request
1 task
Copy link
Collaborator

@Yun-Jinwoo Yun-Jinwoo left a comment

Choose a reason for hiding this comment

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

확인했습니다! 고생하셨습니다~!👍

value,
onChange,
}: ImageUploadProps) {
const fileInputRef = useRef<HTMLInputElement | null>(null);
Copy link
Collaborator

Choose a reason for hiding this comment

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

저도 ref 사용하면서 알았는데 | null 이 없어도 ts에서 자동으로 null도 추론하더라구요!
근데 찾아보니 명시적으로 써놓는 경우도 많다고 해서 그냥 참고하시면 좋을것 같습니다!
image

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

오.. ts가 똑똑해서 자동 추론이 되는군요! 좋은 정보 감사합니다!

Copy link
Contributor

Choose a reason for hiding this comment

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

이미 generic으로 지정을 해서 추론은 아닐 거고, 원래 사용할 때 hook에서 기본적으로 null을 union type으로 포함한다고 보시면 될 거 같아요~

Copy link
Contributor

@Moon-ju-young Moon-ju-young left a comment

Choose a reason for hiding this comment

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

image
정보 변경 페이지에서는 이렇게 보이는 거 같은데 추가해주시면 좋을 것 같아요~

onChange,
}: ImageUploadProps) {
const fileInputRef = useRef<HTMLInputElement | null>(null);
const [preview, setPreview] = useState<string>(value);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const [preview, setPreview] = useState<string>(value);
const [preview, setPreview] = useState(value);

💬 자동적으로 type 추론이 되어서 이렇게 적어도 될 것 같습니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

넵 알겠습니다!

setPreview(value);
}, [value]);

const handleButtonClick = () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

💬 버튼이 아니기도 하고 다른 Click Event handler가 없어서 그냥 handleClick으로 이름을 해도 괜찮을 것 같습니다~

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

넵 좋습니다!

Comment on lines 41 to 61
<label className="text-body1/26 font-regular text-black">{label}</label>

<div
onClick={handleButtonClick}
className="flex h-200 w-full cursor-pointer items-center justify-center rounded-xl border border-gray-30 bg-gray-10 md:h-276 md:w-483"
>
{preview ? (
<img
src={preview}
alt="미리보기"
className="size-full rounded-xl object-cover"
/>
) : (
<div className="flex flex-col items-center gap-11">
<img src={Camera} alt="카메라" className="size-32" />
<span className="text-body1/20 font-bold text-gray-40">
이미지 추가하기
</span>
</div>
)}
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

💬 이 부분에 대해선 개인차이긴 한데, 보통은 label을 이미지 미리보기로 많이 활용하는 편입니다! 기본적으로 labelinput을 연결해 주면 label을 눌렀을 때 input을 클릭했을 때와 동일한 동작을 보여서 label로 사용한다면 handleButtonClick 함수가 필요 없을 듯 합니다~

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

오 좋은 방법이네요 한 번 바꿔보겠습니다!

onChange: (file: File, previewUrl: string) => void;
}

export default function ImageUpload({
Copy link
Contributor

Choose a reason for hiding this comment

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

💬 이 역시 input의 한 종류라서 ImageInput 등 input이라는 이름을 포함하면 좋을 것 같습니다~

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

넵 알겠습니다!


export default function ImageUpload({
label,
value,
Copy link
Contributor

Choose a reason for hiding this comment

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

❓ 기본 이미지 값을 나타내는 prop일까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

넵 맞습니다! 근데 이름이 좀 애매하니 value에서 imageUrl로 변경하겠습니다!

interface ImageUploadProps {
label: string;
value: string;
onChange: (file: File, previewUrl: string) => void;
Copy link
Contributor

Choose a reason for hiding this comment

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

❓ 어떤 함수인지 잘 모르겠습니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

이미지를 바꾸는 함수인데 이름이 모호한 것 같네요 변경하겠습니다!


<div
onClick={handleButtonClick}
className="flex h-200 w-full cursor-pointer items-center justify-center rounded-xl border border-gray-30 bg-gray-10 md:h-276 md:w-483"
Copy link
Contributor

Choose a reason for hiding this comment

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

💬 너비를 설정해야 한다면 상위 태그에서 조정하는 것이 맞을 것 같습니다! 그리고 w-full로 두거나 className을 받아서 상위에서 너비를 조절하게 한다면 더 좋을 것 같습니다~

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

넵 알겠습니다!

value,
onChange,
}: ImageUploadProps) {
const fileInputRef = useRef<HTMLInputElement | null>(null);
Copy link
Contributor

Choose a reason for hiding this comment

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

이미 generic으로 지정을 해서 추론은 아닐 거고, 원래 사용할 때 hook에서 기본적으로 null을 union type으로 포함한다고 보시면 될 거 같아요~

Comment on lines 30 to 36
const reader = new FileReader();
reader.onloadend = () => {
const previewUrl = reader.result as string;
setPreview(previewUrl);
onChange(file, previewUrl);
};
reader.readAsDataURL(file);
Copy link
Contributor

Choose a reason for hiding this comment

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

❓ 아마 배울 때는 URL.createObjectURL을 사용했던 것 같은데, FileReader를 쓰신 이유가 있으신가요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

아 그렇네요 까먹고 있었습니다! 바꾸도록 하겠습니다!

@minimo-9 minimo-9 merged commit b7553e0 into develop Jun 17, 2025
2 checks passed
@minimo-9 minimo-9 deleted the feat/92-image-upload branch June 17, 2025 13:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ 기능 추가/구현 새로운 기능을 추가하거나 구현했어요! 🎨 UI/스타일 관련 스타일을 추가하거나 변경했어요!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] 이미지 업로드 컴포넌트 구현

4 participants