본문 바로가기

프로젝트/오심테(오늘의 심리테스트)

[NextJS & Firestore] NextJS에 Firestore 연동해보기

반응형

오늘은 더미데이터를 Firestore로 이동해주는 작업을 했다. Firestore를 이용한 이유는 쉽게 데이터베이스를 구축할 수 있기 때문이다.

Firebase 8버전을 써봤다가 9버전을 써봤다가.. 계속 에러를 만났다. 결국 가장 최신 버전을 사용하는데 성공했고, 연동함에 있어 버벅임이 조금 있었지만 연동 후 데이터 자체를 받아오는 작업은 그리 어렵지 않았다.

먼저, Firebase 사이트에 들어가 Firestore Database를 만들고, 데이터를 임시로 하나만 입력해놓았다.

이제 나의 리액트 프로젝트와 이 데이터베이스를 연동해야 한다. 프로젝트에 FirebaseConfig.js(이름은 아무거나 하면 됨)라는 파일을 하나 만들고, 다음과 같은 코드를 삽입해준다. 아래 코드는 프로젝트 설정에 들어가 하단을 보면 찾을 수 있다.

처음에는 .env 파일을 만들어서 apikey 등을 전역변수로 관리해주려고 했는데 계속 에러가 났다. 스택오버플로우를 찾아보니 env를 사용하지말고 그냥 복붙하라는 댓글이 많아 나도 그냥 넣어줬더니 거짓말처럼 성공했다. 이래도 되는건가는 모르겠지만, 계속 에러가 나서...

import { initializeApp } from "firebase/app";
import { getFirestore } from "@firebase/firestore";

// Your web app's Firebase configuration
const firebaseConfig = {
  apiKey: "AIzaSyARCs5Rk7OV-pnVHyxYQkISO4FKAffIULw",
  authDomain: "react-practice-1d62f.firebaseapp.com",
  databaseURL: "https://react-practice-1d62f-default-rtdb.firebaseio.com",
  projectId: "react-practice-1d62f",
  storageBucket: "react-practice-1d62f.appspot.com",
  messagingSenderId: "744256872818",
  appId: "1:744256872818:web:9c9d04190b17b0626bbdeb",
};

const app = initializeApp(firebaseConfig);

export const db = getFirestore(app);

 

규칙도 다음과 같이 바꿔주자.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true;
    }
  }
}

 

이제 연동은 끝났다. 미리 입력해둔 한 건의 데이터를 가져와보자.

export default function Home() {
  const [list, setList] = useState([]);
  const listsCollectionRef = collection(db, "testList");

  useEffect(() => {
    // 비동기로 데이터 받을준비
    const getLists = async () => {
      // getDocs로 컬렉션안에 데이터 가져오기
      const data = await getDocs(listsCollectionRef);
      setList(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
    };

    getLists();
  }, []);

  return (
    <Layout>
      <TestList testList={list} />
    </Layout>
  );
}

NextJS를 사용하지 않은 프로젝트에서는 위와 같이 전반적으로 useEffect안에 data를 가져오는 코드를 넣어 그것을 상태로 관리해주었다. NextJS에서도 useState, useEffect로 처리해줘도 데이터는 문제 없이 잘 뜬다. 하지만 이렇게 되면 NextJS를 사용하는 의미가 없어진다.

useEffect를 사용하면 데이터는 페이지가 한 번 렌더링된 이후 가져와지고, 데이터가 가져와진 후 페이지가 리렌더링되면서 그것을 보여주는 순서로 작동한다. 우리가 NextJS를 쓰는 가장 큰 이유는 SEO다. 사용자들에게 많이 노출되게끔 하는 것, 그것이 중요하다. 하지만 useEffect를 사용하면 오른 클릭 후 '페이지 소스검사'를 했을 때 우리가 가져온 데이터들이 포함되지 않는 것을 볼 수 있다. 이렇게 되면 SEO에 도움이 되지 않는다. NextJS를 사용해 SSR을 적용시켜야 한다.

그렇다면 NextJS에서 제공하는 방식을 통해 페이지가 렌더링 되기 전에 데이터가 불러와지도록 수정해보자. NextJS에서는 사전 렌더링을 위해 총 두 가지 방법을 제공하는데, 오늘은 그 중 SSG(Static-Site-Generation), 정적 생성 방식을 사용한다.

정적 생성에서 페이지 컴포넌트가 사전 렌더링 되는 시점은 애플리케이션이나 NextJS를 빌드하는 시점이다. 정적 생성에서는 기본적으로 요청이 서버에 도달했을 때 서버에서 즉각적으로 페이지를 사전 렌더링하지 않고 개발자가 사이트를 빌드할 때(배포) 렌더링 된다.

NextJS에서는 정적 생성을 위해 getStaticProps()라는 메서드를 제공해주고, 이 메서드는 NextJS를 사용할 때 매우 많이 쓰인다.

페이지 컴포넌트에 데이터를 가져와서 추가해야 할 시, 페이지 컴포넌트 파일 안에서 getStaticProps 메서드를 사용한다. 이 메서드는 사전 렌더링 과정 중 실행되며, 실제로 이 페이지에서 사용할 props를 준비하고, 이는 비동기적으로 설정될 수 있어 promise를 반환한다. NextJS는 이 promise가 해결 완료될 때까지 기다린 뒤, 컴포넌트 함수에서 사용할 props를 반환한다. 이렇게 하면 컴포넌트가 실행되기 전에 데이터를 읽어 들여 해당 컴포넌트가 필요한 데이터와 함께 렌더링 되도록 할 수 있다.

// index.js
import { db } from "../firebaseConfig";
import { collection, getDocs } from "firebase/firestore";

export default function Home({ lists }) {
  return (
    <Layout>
      <TestList testList={lists} />
    </Layout>
  );
}

export async function getStaticProps() {
  const listsCollectionRef = collection(db, "testList");
  const data = await getDocs(listsCollectionRef);
  const testArr = data.docs.map((doc) => ({ ...doc.data(), id: doc.id }));

  return {
    props: {
      lists: testArr,
    },
  };
}

위와 같이 기존에 더미데이터로 처리해주었던 방식을 갈아엎고, getStaticProps 내에서 파이어스토어에 있는 데이터를 가져와 뿌려주는 방식을 통해 구현하였다. 이렇게 하면 더 이상 useState와 useEffect를 사용하지 않아도 될 뿐 아니라, 페이지가 렌더링 되기 전에 데이터가 서버로부터 받아와져있기 때문에 더 나은 사용자 경험을 만들 수 있다고 한다.

비록 정리한 글은 짧지만 이거 하는데 4시간은 걸렸다.

이제 다음에 할 일은 심리테스트를 누르면 아이템 별 데이터를 가져오는 것! url에서 id 값을 따오는 방식을 사용해야할 것 같다. 이게 완료되면 카테고리별 데이터 filter도 도전해보려고 한다.

 

firebase를 만지니 대학교 4학년 인턴 시절 비대면 의료 채팅 서비스를 만들었던 기억이 난다. 그 때도 firebase를 이용했었는데..

함께 공부하는 스터디 동료 분과 sql 시험을 본 후 6월 중순 쯤부터 함께 프로젝트를 해보기로 했다. 둘 다 꼭 만들고 싶은 기능으로 '채팅'이 나왔다. 그래서 그런가 예전 생각이 많이 난다. 그때는 지금보다 스택오버플로우에 더 집착했었던 것 같다. 에러만 나와도 기겁을 했던 22살.. 그래도 그때가 그립다ㅋㅋㅋㅋㅋㅋ다시 돌아가면 더 열심히 할텐데;

안드로이드 개발도 꽤 재밌었다(기억 조작인 듯...그땐 거의 울면서 개발했다. 스트레스 만땅 받아가며..웹 개발이 더 재밌어^^). 렌더링(?) 시간이 매우 오래 걸려서 좀 지루하긴 했지만ㅎ.. 자바 다 까먹은 것 같다. 사실 그때는 뭣도 모르고 인터넷에 있는 코드 복붙해가며 만들고 구글을 선생님 삼아 개발하고 난리도 아니였다 ㅋㅋㅋㅋ 원래 다 이렇게 시작하는 것 같긴하다. 구글링으로 부터 시작하는 거지..암...그렇고 말고...

여하튼 이번 토이프로젝트도, 다가올 스터디 프로젝트도 예전보다 발전한 모습을 보이고 싶다. 더 열심히 기록해야겠다. 그래도 부트캠프 메인 프로젝트는 주말이나 시간날 때 틈틈히 기록해놨었는데, 프리 프로젝트였던 스택오버플로우 클론 프로젝트 때는 시간도 너무 촉박하고 여유가 없어서 기록을 거의 못했었다. 그게 아직까지도 너무 너무 아쉽다. 예전에 썼던 글보면서 울고 웃고 힐링하는 재미가 있는건데 ㅠㅠ

 

참고한 블로그)

https://devkevin0408.tistory.com/204

 

Firebase v9 + React 로 CRUD

Firebase는 platform provided by google. 코드에 주석으로 뭐하는 코드인지 메모를 조금 해뒀다. 사진이 안보이면 클릭하면 커진다. 참고하면 좋은 자료들 1. https://travis.media/how-to-use-firebase-with-react/#20211130

devkevin0408.tistory.com

https://fomaios.tistory.com/entry/Firebase-Error-%ED%95%B4%EA%B2%B0%EB%B2%95-%ED%8F%AC%ED%95%A8-Missing-or-insufficient-permissions

 

[Firebase Error 해결법 포함] Missing or insufficient permissions

안녕하세요 Foma 입니다! 오늘 만난 에러는 시뮬레이터로 Firebase에서 데이터를 받아오려고 하는데 갑자기 아래와 같이 Missing or insufficient permissions 라고 뜨고 데이터가 받아지지 않는거에요... 그

fomaios.tistory.com

 

반응형