Feed 컴포넌트를 만들고, 그 안에 글을 작성할 수 있는 Input 부분을 완성하였다. 이번에는 저장된 글들을 DB에서 불러와 이를 보여주도록 한다. 이를 위해선 컴포넌트 실행시 글을 보여줄 수 있도록 useEffect를 사용하고, 저장된 글을 불러오기 위해 Firebase의 DB를 이용해야 하고, 저장된 내용들을 하나하나 띄워줄 수 있도록 반복문을 사용해야 한다. 이 때 JSX부분에서 반복기능을 구현하기 위해 Map함수를 사용하도록 한다.
먼저 Feed.js를 작성한다
import React, { useState, useEffect } from 'react'
import './Feed.css'
import CreateIcon from '@material-ui/icons/Create'
import InputOption from './InputOption'
import ImageIcon from '@material-ui/icons/Image'
import SubscriptionsIcon from '@material-ui/icons/Subscriptions'
import EventNoteIcon from '@material-ui/icons/EventNote'
import CalendarViewDayIcon from '@material-ui/icons/CalendarViewDay'
import Post from './Post'
import { db } from './firebase'
import firebase from 'firebase'
import { useSelector } from 'react-redux'
import { selectUser } from './features/userSlice'
import FlipMove from "react-flip-move"
function Feed() {
const user = useSelector(selectUser);
const [input, setInput] = useState('');
const [posts, setPosts] = useState([]);
//메인화면이 보이고, Feed컴포넌트가 실행되면,
//저장되어 있던 글들을 불러와야 한다
useEffect(()=>{
//posts collection에 저장되어 있던 글들을 시간순으로 캡처한다
db.collection("posts").orderBy('timestamp', 'desc').onSnapshot((snapshot)=>
setPosts(
//DB에 저장된 글들을 map 함수를 이용해 하나하나씩 꺼내서 Posts State에 담아준다
//이렇게 Posts State에 담으면, 나중에 State에 담긴 글들을 하나씩 꺼내면된다.
snapshot.docs.map((doc)=>({
id: doc.id,
data: doc.data()
}))
)
);
},[]);
const sendPost = e => {
e.preventDefault();
db.collection("posts").add({
name: user.displayName,
description: user.email,
message: input,
photoUrl: user.photoUrl || "",
timestamp: firebase.firestore.FieldValue.serverTimestamp()
});
setInput("");
};
return (
<div className="feed">
//글을 작성할 수 있는 부분
<div className="feed__inputContainer">
<div className="feed__input">
<CreateIcon />
<form>
<input type="text" value={input} onChange={e=>setInput(e.target.value)} />
<button type="submit" onClick={sendPost}>Send</button>
</form>
</div>
<div className="feed__inputOptions">
<InputOption Icon={ImageIcon} title="Photo" color="#70B5F9" />
<InputOption Icon={SubscriptionsIcon} title="Video" color="#E7A33E" />
<InputOption Icon={EventNoteIcon} title="Event" color="#C0CBCD" />
<InputOption Icon={CalendarViewDayIcon} title="Write article" color="#7FC15E" />
</div>
</div>
//작성된 글들을 보여줄 때 애니메이션 효과를 넣는다
//React-flip-move 라이브러리 사용
<FlipMove>
{
//앞서 DB에서 꺼내서 posts state에 담긴 글들을 다시 하나 하나 꺼내준다
//글을 꺼낼 때, id, 작성자, 이메일, 글내용의 정보를 꺼내 Post 컴포넌트에 전달
posts.map(({id, data:{name, description, message, photoUrl}})=>(
<Post
key={id}
name={name}
description={description}
message={message}
photoUrl={photoUrl}
/>
))
}
</FlipMove>
</div>
)
}
export default Feed
저장된 글들을 보여주기 위해선 3가지 단계를 거쳐야 한다.
1) DB에 저장된 글들을 하나하나 꺼내서 posts state에 담아둔다.
2) posts state에 담긴 글들을 다시 하나하나 꺼내서 그 안에 담긴 정보를 Post 컴포넌트에 전달한다
3) Post 컴포넌트는 props로 전달받은 정보들을 UI로 띄워준다
이번에는 Post 컴포넌트를 완성해본다. 이를 위해 Post.js를 작성한다.
import { Avatar } from '@material-ui/core'
import { ChatOutlined, SendOutlined, ShareOutlined, ThumbUpAltOutlined } from '@material-ui/icons'
import React, { forwardRef } from 'react'
import InputOption from './InputOption'
import './Post.css'
//FlipMove로 애니메이션 효과를 주기 위해 rfce 형식을 수정하였다
const Post = forwardRef(({ name, description, message, photoUrl }, ref) => {
return (
<div ref={ref} className="post">
//앞서서 posts state에 담긴 정보를 Post 컴포넌트로 전달하였다
//이 정보들을 데이터 바인딩 해준다
<div className="post__header">
<Avatar src={photoUrl}>{name[0]}</Avatar>
<div className="post__info">
<h2>{name}</h2>
<p>{description}</p>
</div>
</div>
<div className="post__body">
<p>{message}</p>
</div>
//각 글들 마다 필요한 상세 기능들을 띄워준다.
<div className="post__buttons">
<InputOption Icon={ThumbUpAltOutlined} title="Like" color="gray" />
<InputOption Icon={ChatOutlined} title="Comment" color="gray" />
<InputOption Icon={ShareOutlined} title="Share" color="gray" />
<InputOption Icon={SendOutlined} title="Send" color="gray" />
</div>
</div>
)
})
export default Post
'Projects > React + Firebase 링크드인 클론' 카테고리의 다른 글
#9. 작성한 모든 컴포넌트를 합쳐주기 | App.js (0) | 2021.05.31 |
---|---|
#8. 위젯 부분 구현 | Widgets.js (0) | 2021.05.31 |
#6. 피드와 포스트 입력창 구현 | Feeds, InputOption (0) | 2021.05.31 |
#5. 메인화면 및 사이드바 구현 | Sidebar.js (0) | 2021.05.31 |
#4. 로그인 부분 구현 | Login.js (0) | 2021.05.31 |