728x90
반응형
이번에는 현재 로그인된 사용자의 tweets(게시물)만 가져오는 작업을 할겁니다.
tweets 상태를 만들어주고
const [tweets, setTweets] = useState<ITweet[]>([]);
const fetchTweets = async() => {
const tweetQuery = query(
collection(db, "tweets"),
where("userId", "==", user?.uid),
orderBy("createdAt", "desc"),
limit(25)
);
const snapshot = await getDocs(tweetQuery);
const tweets = snapshot.docs.map((doc) => {
const { tweet, createdAt, userId, username, photo } = doc.data();
return {
tweet,
createdAt,
userId,
username,
photo,
id: doc.id,
};
});
setTweets(tweets);
};
useEffect(() => {
fetchTweets();
}, [])
fetchTweet을 작성합니다. 이전에 게시글을 가져오는것과 동일합니다. 대신 사용자의 uid가 동일한것만 가져오는 구문이 추가되었습니다.
이후 아래에 tweet을 나타낼 컨테이너를 작성합니다.
const Tweets = styled.div`
display: flex;
flex-direction: column;
gap: 10px;
`;
# ...중략
<Tweets>
{tweets.map(tweet => <Tweet key={tweet.id} {...tweet}/>)}
</Tweets>
그러면 브라우저에서는 해당 오류가 발생합니다. 이는 firebase에서 예기치 못한 필터가 발생했다는 것을 말합니다.
해당 url을 클릭하고 save버튼을 누르고 Enabled 될때까지 기다려줍니다.
이후 다시 새로고침 해보면
이같이 자신의 게시물이 뜨는것을 확인할 수 있습니다.
전체코드
import styled from "styled-components";
import { auth, db, storage } from "../firebase";
import { useEffect, useState } from "react";
import { getDownloadURL, ref, uploadBytes } from "firebase/storage";
import { updateProfile } from "firebase/auth";
import { collection, getDocs, limit, orderBy, query, where } from "firebase/firestore";
import { ITweet } from "../components/timeline";
import Tweet from "../components/tweet";
const Wrapper = styled.div`
display: flex;
align-items: center;
flex-direction: column;
gap: 20px;
`;
const AvatarUpload = styled.label`
width: 80px;
overflow: hidden;
height: 80px;
border-radius: 50%;
background-color: #1d9bf0;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
svg {
width: 50px;
}
`;
const AvatarImg = styled.img`
width: 100%;
`;
const AvatarInput = styled.input`
display: none;
`;
const Name = styled.span`
font-size: 22px;
`;
const Tweets = styled.div`
display: flex;
flex-direction: column;
gap: 10px;
`;
export default function Profile() {
const user = auth.currentUser;
const [avatar, setAvatar] = useState(user?.photoURL);
const [tweets, setTweets] = useState<ITweet[]>([]);
const onAvatarChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const {files} = e.target;
if (!user) return;
if (files && files.length){
const file = files[0];
const locationRef = ref(storage, `avatars/${user?.uid}`);
const result = await uploadBytes(locationRef, file);
const avatarUrl = await getDownloadURL(result.ref);
setAvatar(avatarUrl);
await updateProfile(user, {
photoURL: avatarUrl,
});
}
};
const fetchTweets = async() => {
const tweetQuery = query(
collection(db, "tweets"),
where("userId", "==", user?.uid),
orderBy("createdAt", "desc"),
limit(25)
);
const snapshot = await getDocs(tweetQuery);
const tweets = snapshot.docs.map((doc) => {
const { tweet, createdAt, userId, username, photo } = doc.data();
return {
tweet,
createdAt,
userId,
username,
photo,
id: doc.id,
};
});
setTweets(tweets);
};
useEffect(() => {
fetchTweets();
}, [])
return <Wrapper>
<AvatarUpload htmlFor="avatar">
{avatar ? <AvatarImg src={avatar} /> : <svg fill="none" strokeWidth={1.5} stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path strokeLinecap="round" strokeLinejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z" />
</svg>}
</AvatarUpload>
<AvatarInput onChange={onAvatarChange} id="avatar" type="file" accept="image/*" />
<Name>
{user?.displayName ?? "Anonymous"}
</Name>
<Tweets>
{tweets.map(tweet => <Tweet key={tweet.id} {...tweet}/>)}
</Tweets>
</Wrapper>;
}
728x90
반응형
'Front-end > twitter_clone' 카테고리의 다른 글
[트위터 클론코딩 챌랜지] API key & Security Rules_21 (0) | 2024.04.11 |
---|---|
[트위터 클론코딩 챌랜지] Deploy_20 (0) | 2024.04.11 |
[트위터 클론코딩 챌랜지] Profile 만들기_18 (2) | 2024.04.08 |
[트위터 클론코딩 챌랜지] Edit 만들기_17 (0) | 2024.04.05 |
[트위터 클론코딩 챌랜지] 트윗 Delete_16 (0) | 2024.04.04 |