본문 바로가기

코딩

트위터 클론코딩: 2파일첨부하고 썸네일 나타내기

728x90

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("트윗을 삭제하는 데 실패했습니다!");
}
}
};
```