[TIL #29] 뉴스피드 만들기, Firebase를 이용하여 데이터 읽어오기

Bora.K | 권보라·2023년 11월 22일
1

TIL

목록 보기
29/51
post-thumbnail

오늘 한 일


  • [팀Project] 뉴스피드 만들기
    • 팀회의: 공용 컴포넌트 생성
    • Firebase로 데이터 가져오기
    • Firebase 데이터 활용하여 피드 리스트 기능 구현

학습 내용


팀 프로젝트 : 뉴스피드 만들기

1. 뉴스피드란?

내 게시물을 포함하여 다른 사람들의 모든 게시물을 볼 수 있는 공간이다. 우리 조는 오운완, 오식완 등 운동과 식단을 공유하는 플랫폼을 만들기로 정하고 팀 프로젝트를 진행했다.

이 중 내가 맡은 부분은 Home 페이지의 피드 리스트 구현과 상단의 캐로셀 슬라이더 구현, 그리고 푸터 UI었다. 어제 기본적인 UI 셋팅을 완료하고 오늘 기능 구현에 들어갔다.

2. VS Code 확장팩 Live Share

오늘 VS Code의 Live Share라는 확장팩을 통해 팀원들 모두가 VS Code에서 모여서 실시간으로 코드 수정 및 공용 컴포넌트를 생성했다. 라이브 쉐어라는 확장팩 진짜 너무 좋은 기능…조원들이 동시에 같이 한 공간에서 코드 수정이 가능하고, 이것이 실시간 반영되어 react에도 나타난다. Follow 기능도 있어서 상대방이 파일을 이동하고 수정하는 모습을 다 볼 수 있었다.

공용 컴포넌트 생성을 마치고, 각자 분담된 기능 구현을 하기 위해 흩어졌다.


피드 리스트 기능구현

1. Firebase에서 데이터 읽어오기

우선 Firebase 기본 셋팅은 조원 분께서 해주셔서 나는 firestore의 collection 중 하나를 import 해오고 해당 데이터를 읽어오는 작업을 먼저 진행하였다. 내배캠에서 Firebase에 대한 교육 자료를 주셔서 따라하면서 쉽게 읽어올 수 있었다. 혼자 찾아보면서 했다면… 몇 시간이 걸렸을지 모른다.

  • myfiresotre.js에 getFirestore import
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore"; // firestore 관련 import
import { getAuth } from "firebase/auth";

const firebaseConfig = {
  apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
  authDomain: process.env.REACT_APP_FIREBASE_AUTHDOMAIN,
  projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
  storageBucket: process.env.REACT_APP_FIREBASE_STORAGEBUCKET,
  messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGINGSENDER_ID,
  appId: process.env.REACT_APP_FIREBASE_APP_ID
};

export const app = initializeApp(firebaseConfig);
export const AUTH = getAuth(app);
export const POST_DB = getFirestore(app);  // getFirestore를 실행하는 POST_DB 코드 추가

POST_DB를 이용하면 firestore에 있는 데이터를 마음대로 가져올 수 있다. firestore에서 데이터를 가져오기 위해 어떤 collection에서 어떤 data를 가져올 것인지 확인 후 query를 만든다.

쿼리(query)란 무엇일까?
쿼리는 Firestore collection에서 특정 문서에 대한 요청이다.
query(collection(DB, "collection 이름"))을 통해
해당 collection의 모든 문서를 나타내는 쿼리 객체를 생성한다.

검색하려는 문서를 필터링하고 정렬하기 위한 다양한 조건(순서 지정 등)을 포함할 수도 있다.
아래는 활용 예시이다.

const q = query(collection(DB, "posts"), where("author", "==", "John Doe"), orderBy("timestamp", "desc"), limit(10));

  • feedCard.jsx 컴포넌트에 query
import { collection, getDocs, query } from "firebase/firestore";
import { POST_DB } from "fb/myfirebase";

function FeedCard() {
  const [feeds, setFeeds] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      const q = query(collection(POST_DB, "posts"));  // post 콜렉션의 문서 가져오기
      const querySnapshot = await getDocs(q);
      const initialFeeds = [];

      querySnapshot.forEach((doc) => {
        initialFeeds.push({ id: doc.id, ...doc.data() });
      });

      setFeeds(initialFeeds);  // setFeeds에 받아온 데이터 넣기
    };

    fetchData();
  }, []);

query를 통해 POST_DB에 있는 posts 콜렉션에 있는 모든 document를 가져온다. InitialFeeds를 빈 배열로 놓고, 여기에 가져온 doc.data()를 실행하여 document의 데이터를 가져온다. 여기서 doc.id는 지정하지 않아도 자동으로 생성되는 id이다.

Firebase Error
FirebaseError: Missing or insufficient permissions.

여기까지 진행을 했는데, 콘솔 창에 계속 에러 메세지가 떴다!
허가 오류라고 뜨는 것으로 봐서 관련 권한이 없어서 데이터를 읽어오지 못하는 것 같았다.
열심히 찾아보고 조원 분과도 같이 고민한 결과 해결법을 찾았다. 바로 Firebase 규칙에서 읽기, 쓰기 허용이 false로 되어있었다. 이걸 true로 바꿔주었더니 1분 뒤 바로 데이터 불러오기 성공했다!


2. Firebase에서 불러온 데이터 활용

  • feedList.jsx에서 map함수를 돌려 카드 생성
    Firebase에서 받아온 데이터인 feeds를 map함수로 돌려서 카드를 생성했다. 이때 FeedCard에 feed 값을 props로 내려주었다. 피드의 카드를 컴포넌트 분리했기 때문이다. 아직 redux 활용이 쉽지 않아서 일단 props-drilling으로 구현하고 나중에 수정해야지…
return (
    <StListWrapper>
      <StFeedList>
        {feeds.map((feed) => {
          return <FeedCard feed={feed} />;
        })}
      </StFeedList>
    </StListWrapper>
  );

  • FeedCard.jsx 컴포넌트
    feed를 props로 받아서 Firebase에서 데이터들의 postid, like, img, content 값을 카드에 담았다.
import React from "react";
import styled from "styled-components";
import { IoMdHeartEmpty } from "react-icons/io";
import Avatar from "components/avatar";
import FeedHashtag from "./feedHashtag";

function FeedCard({ feed }) {
  return (
    <CardWrapper>
      <StFeedInfo>
        <StUserInfo>
          <Avatar />
          <div>
            <h2>{feed.postid}</h2>
            <p>
              <span>like</span> {feed.like}
            </p>
          </div>
        </StUserInfo>
        <StLikeIcon>
          <IoMdHeartEmpty />
        </StLikeIcon>
      </StFeedInfo>
      <StFeedImg>
        <img src={feed.imgs} alt="피드이미지"></img>
      </StFeedImg>
      <StContentWarapper>
        <FeedHashtag feed={feed} />
        <p>{feed.content}</p>
      </StContentWarapper>
    </CardWrapper>
  );
}

여기서 또 한가지 문제는 이미지와 해시태그는 하나가 아닌 여러 개였다.
해시태그는 FeedHashtag.jsx로 컴포넌트를 분리했기 때문에 해당 컴포넌트로 가서 다시 map 함수를 돌리면 될 것 같은데, 이미지의 경우 Home 페이지에 1개의 이미지만 보여야 하는 것인가? 의문이 들었다. 우선 해시태그부터 구현하기로 했다.
(아래는 우리 조원 분께서 만들어 주신 넘나 귀여운 MockData ㅋㅋㅋ)

  • FeedHashtag.jsx 컴포넌트
    여기도 역시 feed를 props-drilling으로 받아와서 feed.hashtag에 map을 돌려주었다.
    tag를 인자로 받아서 content={tag}로 각각의 해시태그를 생성하였다.
    (onClick 이벤트는 우선 임의로 넣어둔 것!)
import React from "react";
import styled from "styled-components";
import Hashtag from "components/hashtag";

function FeedHashtag({ feed }) {
  return (
    <StTagBox>
      {feed.hashtag.map((tag) => {
        return <Hashtag hashtag={true} content={tag} size={"sm"} onClick={() => alert("안녕")} />;
      })}
    </StTagBox>
  );
}

export default FeedHashtag;

const StTagBox = styled.div`
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 0.5rem;
`;

오늘의 회고


  1. 우선 이미지는 여러 장을 올릴 경우 슬라이드로 넘겨가면서 볼 수 있도록 할 것인지, 첫 번째 이미지만 보이도록 할 것인지 내일 팀원들과 회의를 통해 결정해야 할 듯 하다. 홈에 있는 페이지에는 뉴스피드 형식으로 카드를 보여주는 것이라 대표 이미지 하나만 게시해도 별 문제는 없을 것 같다. 귀찮아서 그러는건 절대 아니다.^^

  2. 이제 map함수 정도는 느리지만 스스로 돌리는 모습에 스스로 좀 뿌듯하다. 아직 모르는 게 많아서 조원 분들께 많이 물어보지만, 다들 너무 친절하게 내 일처럼 알려주셔서 감사하다. 오늘 새롭게 알게된 Live Share 확장팩도 너무 신기하고 Firebase도 신기하다. 우리 조에 능력자들이 많아서 조원 복을 많이 받은 것 같다.


profile
Frontend Engineers

0개의 댓글