supabase CRUD - 이미지 파일 선택 후 미리보기로 렌더링하기
상황
아래와 같이 input type = file만으로 이미지를 선택하게 되면, 해당 이미지가 잘 선택되었는지 사용자가 알기가 어렵다.
사용자 경험을 증대시킬 여러 방식이 있을 수 있겠다. 선택한 파일의 파일명을 렌더링 해주어도 된다.
하지만 직접적으로 어떤 이미지를 선택했는지 보여주고자 한다.
일단 이미지 선택하기 버튼을 누르면 이미지가 supabase 서버로 업로드 되는 로직이 이미 구현되어 있다.
useEffect(() => {
if (image && typeof image !== 'string' && image instanceof File) {
console.log('이미지 선택됨 =>', image);
handleImgUpload(image);
}
}, [image]);
const newImage = (e) => {
const file = e.target.files[0];
if (file) {
setImage(file);
handleImgUpload(file);
}
};
const handleImgUpload = async (file) => {
console.log('file:', file);
if (!file) return; // 이미지파일 없으면 함수 끝
const uniqueImgName = `places/${Date.now()}_${file.name}`;
try {
const { data, error } = await supabase.storage.from('images').upload(uniqueImgName, file);
if (error) throw error;
const { publicUrl } = supabase.storage.from('images').getPublicUrl(uniqueImgName).data;
if (!publicUrl) throw new Error('이미지 유알엘을 못 가져 왔음');
console.log('퍼블릭유알엘임 =>', publicUrl);
setImage(publicUrl);
console.log(publicUrl);
} catch (error) {
console.error('이미지 업로드 실패', error.message);
alert(`이미지 업로드에 실패하였습니다: ${error.message}`);
}
};
supabase images라는 버킷으로 이미지를 업로드 하고, 뒤이어 동기적으로 images에서 getPublicUrl이라는 supabase 내장 메서드를 사용하여 파일의 url을 획득한다.
그리고 이 url을 image라는 state에 담고 있다. 왜냐면 데이터 테이블에 url를 저장할 것이기 때문이다.
방법
이렇게 이미 얻어온 publicUrl을 사용해서 아래처럼 원하는 곳에서 렌더링 하면 끝난다.
만약 사용성을 높이고자 한다면, 스피너와 같이 로딩 처리를 해주면 더 좋아질 것 같다.
{image && <img src={image} alt="미리보기 이미지" style={{ marginTop: '10px', maxWidth: '100%' }} />}
저화질 미리보기 기능 추가 구현
그런데 서버에서 매번 이런 식으로 이미지를 다시 불러오면 트래픽이 많이 소모되기 때문에 저화질로 미리보기 하는 방법도 고민해보면 좋을 것 같다.
먼저 저 url을 그대로 쓰면 안 되고,
프리뷰용으로 변환한 url을 사용한다. 따라서 별도로 상태를 만들어준다.
const [preview, setPreview] = useState();
다음으로 canvas를 활용하여 저화질로 렌더링하는 로직을 구현한다.
const createImagePreview = (file) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = () => {
const img = new Image();
img.src = reader.result;
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const maxWidth = 200; // 최대 너비 설정
const scaleSize = maxWidth / img.width;
canvas.width = maxWidth;
canvas.height = img.height * scaleSize;
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
const dataUrl = canvas.toDataURL('image/jpeg', 0.5); // 저화질 이미지 생성
setImagePreview(dataUrl); // 저화질 이미지 설정
};
};
};
그 다음 사용자가 파일을 선택했을 때 파일을 상태에 저장하는 함수에 위에서 방금 만든 저화질 프리뷰용 함수도 같이 실행해준다.
const newImage = (e) => {
const file = e.target.files[0];
if (file) {
setImage(file);
createImagePreview(file); // 추가
}
};
그리고 필요한 곳에서 새로 만든 상태를 이용하여 조건부 렌더링 하면 된다.
{imagePreview && <img src={imagePreview} alt="미리보기 이미지" style={{ marginTop: '10px', maxWidth: '100%' }} />}
'Programing > Server' 카테고리의 다른 글
Supabase 데이터 전처리 :: 여러 컬럼을 하나의 jsonb로 병합하기 (1) | 2024.06.28 |
---|---|
Supabase 회원가입 + 별도 데이터 테이블에 동시 기록하기 (0) | 2024.06.23 |
supabase 카카오 소셜 로그인 기능 구현하기 (0) | 2024.06.20 |
supabase 유저 이메일 말고 유저 아이디가 일치하면 업데이트 가능하도록 정책 설정하기 (0) | 2024.06.19 |
Supabase 로그인 기능 구현하기 (0) | 2024.06.18 |
댓글