export const storage = getStorage(app)
import { storage } from '@/pages/_app'
import { getDownloadURL, ref, uploadBytes } from 'firebase/storage'
const [imageUrl, setImageUrl] = useState('')
const onChangeUpload = (event: ChangeEvent<HTMLInputElement>) => {
if (event.target.files === null) return;
const imageRef = ref(storage, `images/${event.target.files[0].name}`)
uploadBytes(imageRef, event.target.files[0])
.then((snapshot) => {
getDownloadURL(snapshot.ref)
.then((url: string) => {
setImageUrl(url)
});
});
};
<Input type='file' onChange={onChangeUpload} />
공식문서
https://firebase.google.com/docs/storage/web/upload-files?hl=ko&authuser=0
- 파이어베이스에서 스토리지를 시작한다.
- storage 만들기 : getStorage() 함수를 파이어베이스에서 불러와 내 앱을 인자로 넣는다.
- 인풋 만들기 : 이미지를 넣을 인풋의 타입을 파일로 설정한다.
- 온체인지 핸들러 만들기 : 이벤트.타겟에 파일이 들어오지 않으면 return 하게 만든다.
- 이미지참조 만들기 : ref() 함수에 인자로 내 스토리지, 내가 업로드할 파일의 이름을 넣는다(경로 포함).
- 업로드 하기 : uploadBytes() 함수에 내가 방금 만든 참조와 파일 이름을 넣어 업로드한다.
- 업로드한 파일의 url을 받기 : getDownloadURL()을 통해 url을 받아 스테이트를 변경해준다.
- 썸네일 노출 : 이제 이 스테이트에 담긴 url을 통해 이미지 태그에 src로 썸네일을 노출 시킬수 있다.
- 글 작성 : onClcikSubmit 핸들러에 글 작성 시 url도 포함하여 제출한다.
아래의 포스트를 참고하여 해결하였다.
- StrictMode 모드 사용.
- route.query를 사용.
특히 Next.js는 route를 사용하게 되면 첫 렌더 시 query가 undefinded 상태로 마운트되고, 그 후 query에 값이 채워져서 다시 렌더링된다. isReady를 사용해서 isReady가 false라면 빈 컴포넌트를 반환하게 만들어 query 값이 채워지기 전까지 렌더링을 늦출 수 있었다.
이때 if( !route.isReady ){ return (<></>) } 코드는 useState()보다 하단에 있어야한다.
그렇지 않으면 "React has detected a change in the order of Hooks called" 라는 에러가 뜨게된다.
파일을 올리는 인풋의 스타일이 마음에 들지 않기 때문에, 기존의 인풋 엘리먼트를 숨기고 useRef 훅스를 사용하여 다른 엘리먼트로 대체하던가, antd를 사용해야겠다.
글 작성 시, 이미지를 업로드하는 인풋이 바뀔때마다 온체인지 핸들러에 의해 이미지를 서버에 저장하고, 그 url을 받아오게된다. 글을 작성하면서 이미지를 계속 변경하게 되면 계속 서버에 버려지는 이미지 데이터가 누적이 될 텐데, 이를 실무에서 어떻게 관리하는지 궁금하다. 내가 내린 생각은 그냥 누적되게 두는 것같다.
기능구현
스타일
리팩토링