1.파일첨부해서 썸네일 나타내기
firebase > storage getStarted!
bucket-> 파일을 넣는 곳
Img File만 받는 Input 태그 생성, 이벤트로 파일 확인
const onFileChange = (event)=>{
const {target:{files}}=event;
const theFile = files[0]; 한개만 사용할꺼임
cosnole.log(theFile);
}
<input type="file" accept="image/*" onChange={onFileChange}/>
File API 이용!
file을 읽어서 url로 바꿔주기
[FileReader API]
https://developer.mozilla.org/ko/docs/Web/API/FileReader
https://developer.mozilla.org/en-US/docs/Web/API/FileReader/onload
const onFileChange = (event) => {
const {
target: { files },
} = event;
const theFile = files[0];
const reader = new FileReader();
reader.onloadend = (finishedEvent) => console.log(finishedEvent); //reader의 동작이끝나면 부름
reader.readAsDataURL(theFile); //파일을 문자열로 바꿔서 업로드 후 브라우저에서 문자->사진으로 다시바꿔줌
};
url img 태그 안에 넣기 , clear버튼만들기
useState를 이용하여 사용할 수 있도록
//사진 첨부 없이 텍스트만 트윗하고 싶을 때도 있으므로 기본 값을 ""로 해야한다.
//트윗할 때 텍스트만 입력시 이미지 url ""로 비워두기 위함
const [attachment, setAttachment] = useState("");
const onFileChange = (event) => {
const {
target: { files },
} = event;
const theFile = files[0];
const reader = new FileReader();
reader.onloadend = (finishedEvent) => {
const {
currentTarget: { result },
} = finishedEvent;
setAttachment(result);
};
reader.readAsDataURL(theFile);
};
const onClearAttachment = ()=>{
setAttachment(null);
}
{attachment && ( //attachment있으면
<div>
<img src={attachment} width="50px" height="50px" />
<button onClick={onClearAttachment}>Clear</button>
</div>
)}
+Clear버튼 클릭 후 file input에 남아 있는 이미지 파일명 지우기
1. useRef()훅을 통해 fileInput변수를 만들고 file input과 연결시켜줍니다.
const fileInput = useRef();
input type="file" accept="image/*" onChange={onClearAttachment} ref={fileInput}
2. Clear버튼을 눌렀을 때 fileInput객체 안에 current의 value값을 가져와서 비워줍니다.
onClearAttachment = () => {
fileInput.current.value = "";
}
2.파일업로드하기
submit에 tweet을 upload하는건 잠깐 주석처리 하고
사진을 먼저 업로드 후 url을 받아서 tweet에 올릴꺼임
fbase.js
mport { getStorage } from "firebase/storage";
export const dbService = getStorage(app);
home.js
const fileRef = ref(storageService, `${userObj.uid}/${v4()}`);
ref 는 공기중에 떠 있는 파일 upload한게 아니고 그냥 reference이다
파일에 대한 reference만든 후 파일 데이터를 refernce로 보냄.
npm i uuid
유니크한 아이디를 만들어줌
업로드할 파일의 이름정할 때 사용할것임.
put은 업로드를 위한 html method이다.
value format
const response = await uploadString(fileRef, attachment, "data_url");
console.log(response);
const attachmentUrl = await getDownloadURL(response.ref);
try {
await addDoc(collection(db, "nweets"), {
text: nweet,
createdAt: Date.now(),
creatorId: userObj.uid,
attachmentUrl,}
submit하면 storage에 들어와있음
Nweet.jsx
{nweetObj.attachmentUrl && (
<img
src={nweetObj.attachmentUrl}
width="50px"
height="50px"
/>
)}
Home.jsx
const onSubmit = async (event) => {
event.preventDefault();
+ let attachment ="";
if (attachment !== "") { //사진 첨부했을 때만
const attachmentRef = ref(storageService, `${userObj.uid}/${v4()}`);
const response = await uploadString(
attachmentRef,
attachment,
"data_url"
);
const attachmentUrl = await getDownloadURL(response.ref);
+ attachmentUrl = await getDownloadURL(response.ref);
} //lexical scope 정적 범위 어휘 범위 attachment url이 if 문 안에 작성되어있어서
try {
await addDoc(collection(db, "nweets"), {
text: nweet,
createdAt: Date.now(),
creatorId: userObj.uid,
attachmentUrl, ///밖에서 사용할 수 없다. 파란색처럼 밖에 전역변수 선언하여 할당
});
} catch (e) {
console.error("Error adding document: ", e);
}
setNweet("");
};
이대로 실행하니까 사진이 업로드되지 않은 채로는 Nweet이 되지 않았습니다
attachment의 기본값이 useState( ) 로 되어있기 때문이었다고 봅니다.
완성본의 깃허브 소스를 참고해서 몇가지를 수정하니 잘 작동되는군요
혹시 저와 같은 고민을 하시는 분이 있을 지 몰라 남겨봅니다.
1. const [attachment, setAttachment] = useState("")로 바꿔주기
2. const onClearAttachment = () => { setAttachment("") }로 바꿔주기
전체 코드 확인하기
//getDownloadURL 임포트
import { ref, uploadString, getDownloadURL } from "@firebase/storage";
//사진 첨부 없이 텍스트만 트윗하고 싶을 때도 있으므로 기본 값을 ""로 해야한다.
//트윗할 때 텍스트만 입력시 이미지 url ""로 비워두기 위함
const [attachment, setAttachment] = useState("");
const onSubmit = async (event) => {
event.preventDefault();
let attachmentUrl = "";
//이미지 첨부하지 않고 텍스트만 올리고 싶을 때도 있기 때문에 attachment가 있을때만 아래 코드 실행
//이미지 첨부하지 않은 경우엔 attachmentUrl=""이 된다.
if (attachment !== "") {
//파일 경로 참조 (폴더) 만들기,
const attachmentRef = ref(storageService, `${userObj.uid}/${uuidv4()}`);
//storage 폴더에 이미지 넣기
const response = await uploadString(attachmentRef, attachment, "data_url");
//storage 파일 위치에있는 파일 URL을 다운로드해서 attachmentUrl 변수에 넣어서 업데이트
이미지의 Reference에 접근 가능, 이미지가 저장된 stroage 주소를 받을 수 있다
response.ref 대신 attachmentRef로 작성해도 동일하게 작동합니다!
attachmentUrl = await getDownloadURL(response.ref);
}
//트윗 오브젝트
const nweetObj = {
text: nweet,
createdAt: Date.now(),
creatorId: userObj.uid,
attachmentUrl,
};
//트윗하기 누르면 nweetObj 형태로 새로운 document 생성하여 nweets 콜렉션에 넣기
await addDoc(collection(dbService, "nweets"), nweetObj);
//state 비워서 form 비우기
setNweet("");
//파일 미리보기 img src 비워주기
setAttachment("");
};
//첨부 파일 url 넣는 state인 attachment 비워서 프리뷰 img src 없애기
const onClearAttachment = () => {
//null에서 빈 값("")으로 수정, 트윗할 때 텍스트만 입력시 이미지 url ""로 비워두기 위함
setAttachment("");
};
돈을 더 내고싶지 않다면
tweet 삭제 시 파일도 삭제 되는 걸 알아볼 꺼임
웹에서 Cloud Storage로 파일 삭제
https://firebase.google.com/docs/storage/web/delete-files
```
import { dbService, storageService } from "fbase";
import { deleteObject, ref } from "firebase/storage";
//생략...
//삭제하려는 이미지 파일 가리키는 ref 생성하기
// nweetObj의 attachmentUrl이 바로 삭제하려는 그 url임
const desertRef = ref(storageService, nweetObj.attachmentUrl);
//트윗 삭제
const onDeleteClick = async () => {
const ok = window.confirm("정말 이 트윗을 삭제하시겠습니까?");
if (ok) {
try {
//해당하는 트윗 파이어스토어에서 삭제
await deleteDoc(nweetTextRef);
//삭제하려는 트윗에 이미지 파일이 있는 경우 이미지 파일 스토리지에서 삭제
if (nweetObj.attachmentUrl !== "") {
await deleteObject(desertRef);
}
} catch (error) {
window.alert("트윗을 삭제하는 데 실패했습니다!");
}
}
};
```
'코딩' 카테고리의 다른 글
React component Life Cycle, useEffect Cleanup (0) | 2023.02.15 |
---|---|
[Firebase]Cloud Firestore vs Realtime Database (0) | 2023.02.14 |
react-router-dom v6 route에 prop속성 (0) | 2023.02.12 |
Next js getServerSideProps undefined 해결 (0) | 2023.02.12 |
트위터 클론코딩 :1 (firebase,react) (0) | 2023.02.04 |