게시글 작성 페이지에서 글을 작성하고 supabase에 업데이트 되도록 구현했다
images
는 useState([])
로 상태관리를 하고 있다
이미지는 최대 5개까지 등록이 가능해서 이미지의 개수가 5개 이상이면 alert창을 띄우도록 구현했다
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files) {
const imageFiles = Array.from(e.target.files);
const newImages = [...images, ...imageFiles];
if (newImages.length <= 5) {
setImages(newImages);
} else {
alert('이미지는 최대 5까지만 등록이 가능합니다');
}
}
};
이미지를 등록하지 않은 상태의 UI이다. 여기서 구현하고 싶은 것들이 있었다
3번 같은 경우에는 처음에
p
태그를 사용했는데 내가 원하는대로 구현이 되지 않았다.
그래서label
태그로 텍스트와input
태그를 묶어서 구현을 했다
URL.createObjectURL()
- 보통 로컬환경에서 이미지를 업로드하기 때문에 임의로 URL주소를 만들어 src에 넣어줬다
// 이미지 섹션 컴포넌트 코드
<div className="w-full border-2 border-slate-400 my-[20px] rounded-md p-4">
<div className="flex flex-col items-center justify-center">
<div className="flex flex-wrap mt-4">
{images.map((image, index) => (
<div key={index} className="relative w-[100px] h-[100px] mr-2 mb-2">
<img
src={URL.createObjectURL(image)}
alt={`preview ${index}`}
className="w-full h-full object-cover rounded-md cursor-pointer"
onClick={() => handleImageDelete(index)}
/>
</div>
))}
</div>
{images.length < 1 && (
<label
className="w-[60px] h-[60px] flex items-center justify-center relative rounded-full mt-4 cursor-pointer"
style={{backgroundImage : "url('../images/image_select.jpeg')", backgroundSize : 'cover', backgroundPosition : 'center'}}
>
<input
type="file"
multiple
className="opacity-0 absolute inset-0 w-full h-full cursor-pointer"
onChange={handleImageChange}
/>
</label>
)}
<label className="my-4 underline underline-offset-4 text-blue-600 cursor-pointer">
이미지를 첨부해주세요. (1개 이상 필수, 최대 5개까지 첨부 가능)
<input type="file" multiple className="hidden" onChange={handleImageChange} />
</label>
</div>
</div>
예전에 테이블에 이미지url을 넣어본 경험이 있어서 코드를 참고하며 구현했다
1. supabase storage 버킷에 이미지를 업로드한다
2. storage 버킷에 있는 이미지의 publicUrl을 배열에 담아준다
3. publicUrl을 담은 배열을 supabase 테이블에 저장한다
const uploadedImageUrls = [];
for (let image of images) {
const fileExt = image.name.split('.').pop();
const fileName = `${Date.now()}-${Math.random()}.${fileExt}`;
const filePath = `request_post_image/${fileName}`;
const { error: storageError } = await supabase.storage.from('request_post_image').upload(filePath, image);
if (storageError) {
alert('스토리지 업로드 실패');
} else {
const { data } = await supabase.storage.from('request_post_image').getPublicUrl(filePath);
if (data.publicUrl) {
uploadedImageUrls.push(data.publicUrl);
} else {
alert('URL 가져오기 실패');
return;
}
}
}
테이블에 있는 post_img 컬럼은 text[]
로 지정했다
위에서 publicUrl을 담은 배열을 post_img에 저장한다
const { data, error } = await supabase
.from('Request Posts')
.insert([
{
user_id: crypto.randomUUID(),
title,
content: description,
lang_category: language,
price: '0',
post_img: uploadedImageUrls
}
]);
브라우저에서 내용을 입력하고 등록하기 버튼을 누르면 게시물이 저장되었다는 메세지가 나오기까지 약간의 딜레이 시간이 있다
코드 리팩토링
page.tsx
파일에 코드를 모두 적어둠