Twitter_Clone(3)
😁 로그인 기능을 구현해봤으니 Tweet이 가능하게 만들어 봅니다.
그러기 위해서는 Database가 필요.
📌 Tweet window
💻 Home.js
const Home = () =>{
const [tweet, setTweet] = useState("");
const onSubmit = (event) =>{
event.PreventDefault();
}
const onChange = (event) =>{
const{target:{value}} = event;
setTweet(value);
}
return(
<div>
<form>
<input value = {tweet} onChange= {onChange}type="text" placeholder="What is on your mind?" maxLength={120} />
<input type="submit" value="Tweet" />
</form>
</div>
);
}
📌 Create Tweet
💻fbase.js
import "firebase/firestore";
export const dbService = firebase.firestore();
💻Home.js
const Home = () =>{
const [tweet, setTweet] = useState("");
const onSubmit = async(event) =>{
event.preventDefault();
await dbService.collection("tweets").add({
tweet,
createdAt:Date.now(),
});
setTweet("");
}
const onChange = (event) =>{
const{target:{value}} = event;
setTweet(value);
}
...
</form>
</div>
);
}
📌 코드 설명
- fbase에서 fireStore 가져와 export
- onSubmit은 db에 저장하기에 async, await 사용.
dbService.collection("tweets").add({ tweet, createdAt : Date.now(),
: tweets라는 이름을 가진 collection안에 넣어줌. tweet 값과 createdAt 값.- setTweet("") : 비워주기.
📌 DB -> Home
💻 Home.js
const Home = () =>{
...
const [tweets, setTweets] = useState([]);
const getTweets = async() =>{
const dbtweets =await dbService.collection("tweets").get();
dbtweets.forEach((document) =>{
const tweetObject = {
...document.data(),
id:document.id,
}
setTweets(prev => [tweetObject, ...prev]);
});
}
useEffect(() =>{
getTweets();
},[])
...
return(
...
<div>
{tweets.map((tweet) =>
(<div key={tweet.id}>
<h4>{tweet.tweet}</h4>
</div>
))}
</div>
...
}
📌 코드 설명
const [tweets, setTweets] = useState([]);
: firebase에서 가져올 값.dbService.collection("tweets").get();
: 반환 값이 QuerySnapShat 임. 그러므로 data, id만 forEach로 뽑아주기.- tweetObject에 이전의 data값과, id 넣어주기.
setTweets(prev => [tweetObject, ...prev]);
: prev 값을 [tweetObject, ...prev] 값으로 return.- map을 사용하여 key 값 지정 and tweet 값 화면에 보여주기.
📌 RealTime Tweet
😁 새로고침을 하지 않아도 tweet이 자동으로 새로고침 되게 설정.
💻 Home.js
const Home = ({userObj}) =>{
...
useEffect(() =>{
//getTweets();
dbService.collection("tweets").onSnapshot((snapshot) =>{
const tweetArray = snapshot.docs.map(doc=>({id:doc.id, ...doc.data()}));
setTweets(tweetArray);
})
},[])
...
}
📌 코드 설명
- {userObj}는 App.js로부터 가져온 uid.
- getTweets는 오래된 데이터만 가지고 있기에 realtime을 위해 useEffect안에 넣어준다.
onSnapShot
을 이용 : db가 read, write, update 될 때 update 됨을 알려주는 App에서의 onAuthStateChanged 와 같은 기능.
🧨 주의 : 무조건 Realtime이 좋은 것은 아님. 채팅이나 실시간 업데이트가 필요한 기능에서는 좋으나 그렇지 않은경우 너무 쓸데없는 realtime일 수 있다.
📌 Delete and Update
💻 Tweet.js
const Tweet = ({tweetObj, isOwner}) => (
<div>
<h4>{tweetObj.tweet}</h4>
{isOwner && (
<>
<button>DEL</button>
<button>EDIT</button>
</>
)}
</div>
)
💻 Home.js
{tweets.map((tweet) =>
(<Tweet key={tweet.id} tweetObj = {tweet} isOwner={tweet.creatorId===userObj.uid} />
))}
📌 코드 설명
- Home.js에서 Tweet 부분 너무 커지기에 따로 Tweet.js 나눠줌.
isOwner={tweet.creatorId===userObj.uid}
: tweet.creatorId와 userObj의 uid가 같은 경우 true, 아니면 false 반환. 글을 쓴 사람과 로그인되어있는 사람이 같은지.- Tweet에서
{isOwner && ( <> <button>DEL</button> <button>EDIT</button> </> )}
: isOwner이 true이면 button이 보여짐.
💻 Tweets.js
const Tweet = ({tweetObj, isOwner}) => {
const [editing, setEditing] = useState(false);
const [newTweet, setNewTweet] = useState(tweetObj.tweet);
const onDeleteClick = async() => {
const ok = window.confirm("Are you sure you want to delete this tweet?");
if(ok){
await dbService.doc(`tweets/${tweetObj.id}`).delete();
}
};
const toggleEditing = () =>setEditing((prev) => !prev);
const onSubmit = async(e) => {
e.preventDefault();
await dbService.doc(`tweets/${tweetObj.id}`).update({
tweet:newTweet,
});
setEditing(false);
}
const onChange = (e) =>{
const {target:{value}} = e;
setNewTweet(value);
}
return(
<div>
{
editing ? (
<>
<form onSubmit={onSubmit}>
<input onChange = {onChange}type = "text" placeholder = "Edit" value={newTweet} required />
<input type="submit" value="Update Tweet" />
</form>
<button onClick={toggleEditing}>Cancel</button>
</>
) :
<>
<h4>{tweetObj.tweet}</h4>
{isOwner && (
<>
<button onClick={onDeleteClick}>DEL</button>
<button onClick={toggleEditing}>EDIT</button>
</>
)}
</>
}
</div>
)
}
📌 코드 설명
onDeleteClick
: Delete 버튼을 눌렀을 때 실행되는 함수.- ok는 window 확인창이 나왔을 때의 답변, "예"는 true
- true 일때
dbService.doc().delete()
로 해당 id에 맞는 DB 삭제.
toggleEditing
: Edit의 상태를 !상태로 반환시켜주는 함수.onSubmit
: Edit form에 넣어주는 함수.dbService.doc().update()
로 tweet 내용 업데이트.- setEditing : false로 만들어주어 Edit창 닫아주기.
- return
- editing의 bool 값에 따라 Edit창이 나올지, Tweet 창이 나올지를 결정.
📌 Uploading
💻 fbase.js
import "firebase/storage";
export const storageService = firebase.storage();
💻 Home.js
import {v4 as uuidv4} from "uuid"
const onSubmit = async(event) =>{
event.preventDefault();
const fileRef = storageService.ref().child(`${userObj.uid}/${uuidv4()}`);
const response = await fileRef.putString(attachment, "data_url");
// await dbService.collection("tweets").add({
// tweet : tweet,
// createdAt : Date.now(),
// creatorId : userObj.uid,
// });
// setTweet("");
}
📌 코드 설명
-
import "firebase/storage";
: 사진 업로드에 필요한 import 및 export -
terminal에
npm i uuid
: 랜덤으로 만들어주는 식별자. -
storageService.ref().child(
{uuidv4()});
:ref(구글 클라우드 스토리지의 객체)의 child(이미지의 path)를 만들어 path 설정. -
await fileRef.putString(attachment, "data_url");
: data_url의 data와 data_type(data_url)을 넣어줌.📌 File Url and Tweet
😀 Tweet과 img File 함께 firestore에 올려주기❗❗
💻Home.js
const onSubmit = async(event) =>{
event.preventDefault();
let attachmentUrl = "";
if(attachment != ""){
const fileRef = storageService.ref().child(`${userObj.uid}/${uuidv4()}`);
const response = await fileRef.putString(attachment, "data_url");
attachmentUrl = await response.ref.getDownloadURL();
}
const tweetObj = {
tweet : tweet,
createdAt : Date.now(),
creatorId : userObj.uid,
attachmentUrl,
}
await dbService.collection("tweets").add(tweetObj);
setTweet("");
setAttachment("");
}
💻 TWeet.js
{tweetObj.attachmentUrl && <img src={tweetObj.attachmentUrl} width="50px" height="50px"/>}
📌 코드 설명
if(attachment != "")
: 사진을 안 올릴 경우를 위한 if문.- putSTring의 then으로 반환되는 값중 ref의 getDownloadURL 사용하여 attachmentUrl 변수에 넣어주기.
- tweetObj 객체에 attachment도 넣어주기.
📌 Deleteing File
💻Tweet.js
if(ok){
await dbService.doc(`tweets/${tweetObj.id}`).delete();
await storageService.refFromURL(tweetObj.attachmentUrl).delete();
}
📌 코드 설명
- delete키를 눌렀을 때,
storageService.refFromURL(tweetObj.attachmentUrl).delete();
로 storage의 파일 삭제시켜주기. refFromURL을 이용.
<참고 : 노마드코더>
Author And Source
이 문제에 관하여(Twitter_Clone(3)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@luck2901/CloneTwitter3저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)