[개인 포트폴리오] [트위터 클론 SNS Deli] 분석 Part. 13 'timeline.tsx'
2024. 7. 8. 19:04ㆍ웹개발 포트폴리오
728x90
반응형
timeline.tsx
import styled from "styled-components";
import { Timestamp, collection, deleteDoc, doc, limit, onSnapshot, orderBy, query } from "firebase/firestore";
import { db, storage } from '../firebase';
import Tweet from "./post"; // 트윗 컴포넌트 가져오기
import { Unsubscribe } from "firebase/auth";
import { useEffect, useState } from "react";
import { getDownloadURL, ref } from "firebase/storage";
import { media } from "../media-query-file';
// 트윗 인터페이스 정의
export interface ITweet {
id: string;
photos?: string[];
tweet: string;
userId: string;
username: string;
createdAt: Timestamp;
profileImage?: string;
}
// 스타일드 컴포넌트 정의
const Wrapper = styled.div`
display: flex;
gap: 10px;
flex-direction: column;
overflow-y: scroll;
/* Chrome, Safari, Opera에서 스크롤바 숨기기 */
&::-webkit-scrollbar {
display: none;
}
/* IE, Edge, Firefox에서 스크롤바 숨기기 */
-ms-overflow-style: none;
scrollbar-width: none;
${media.mobile(`
body {
padding: 0 10px !important;
}
`)}
${media.tablet(`
body {
padding: 0 30px !important;
}
`)}
${media.desktop(`
body {
padding: 0 50px !important;
`)}
`;
// 타임라인 컴포넌트 정의
const Timeline = () => {
const [tweets, setTweets] = useState<ITweet[]>([]); // 트윗 상태 정의
useEffect(() => {
let unsubscribe: Unsubscribe | null = null;
const fetchTweets = async () => {
const tweetsQuery = query(
collection(db, "tweets"),
orderBy("createdAt", "desc"),
limit(25) // 최신 25개의 트윗을 가져옴
);
// 실시간으로 트윗을 가져옴
unsubscribe = onSnapshot(tweetsQuery, async (snapshot) => {
const tweetsData = await Promise.all(
snapshot.docs.map(async (doc) => {
const data = doc.data();
let profileImage = "";
try {
// 사용자 프로필 이미지 URL 가져오기
profileImage = await getDownloadURL(ref(storage, `avatars/${data.userId}`));
} catch (e) {
console.log(e);
}
return {
id: doc.id,
tweet: data.tweet,
createdAt: data.createdAt instanceof Timestamp ? data.createdAt : Timestamp.fromDate(new Date(data.createdAt)),
userId: data.userId,
photos: data.photos || [],
profileImage,
username: data.username
};
})
);
setTweets(tweetsData as ITweet[]);
});
};
fetchTweets();
return () => {
if (unsubscribe) {
unsubscribe();
}
};
}, []);
// 트윗 삭제 함수
const onDeleteTweet = async (tweetId: string) => {
const ok = confirm('포스트를 삭제하시겠습니까?');
if (!ok) return;
try {
await deleteDoc(doc(db, 'tweets', tweetId));
setTweets(tweets.filter(tweet => tweet.id !== tweetId)); // 트윗 상태 업데이트
} catch (e) {
console.log(e);
}
};
return (
<Wrapper>
{tweets.map((tweet) => (
<Tweet
key={tweet.id}
id={tweet.id}
photos={tweet.photos || []}
tweet={tweet.tweet}
userId={tweet.userId}
username={tweet.username}
createdAt={tweet.createdAt}
profileImage={tweet.profileImage || ""}
onDeleteTweet={onDeleteTweet}
/>
))}
</Wrapper>
);
};
export default Timeline;
위 코드는 포스트 타임라인을 표시하는 컴포넌트입니다. 주요 기능은 다음과 같습니다:
- 포스트 데이터 가져오기: Firestore에서 최신 25개의 포스트를 실시간으로 가져와서 tweets 상태에 저장합니다. 이를 위해 onSnapshot 함수를 사용하여 실시간 업데이트를 구독합니다.
- 프로필 이미지 가져오기: 포스트 작성자의 프로필 이미지를 Firebase Storage에서 가져와서 포스트 데이터에 포함시킵니다.
- 포스트 삭제: 사용자가 특정 포스트를 삭제할 수 있습니다. onDeleteTweet 함수가 이를 처리하며, Firestore에서 해당 포스트를 삭제하고 tweets 상태를 업데이트합니다.
- 스타일링: 여러 styled-components를 사용하여 타임라인의 레이아웃과 스타일을 정의합니다. 스크롤바를 숨기기 위해 특정 스타일을 적용했습니다.
728x90
반응형
'웹개발 포트폴리오' 카테고리의 다른 글
[개인 포트폴리오] [트위터 클론 SNS Deli] 분석 Part. 12 'post-tweet-form.tsx' (0) | 2024.07.08 |
---|---|
[개인 포트폴리오] [트위터 클론 SNS Deli] 분석 Part. 11 'post.tsx' (0) | 2024.07.08 |
[개인 포트폴리오] [트위터 클론 SNS Deli] 분석 Part. 10 'profile.tsx' (0) | 2024.07.08 |
[개인 포트폴리오] [트위터 클론 SNS Deli] 분석 Part. 9 'create-account.tsx' & 'login.tsx' (0) | 2024.07.08 |
[개인 포트폴리오] [트위터 클론 SNS Deli] 분석 Part. 8 'home.tsx' (0) | 2024.07.08 |