분류 Reactjs

Firebase를 사용하여 나만의 댓글 시스템을 구축하는 방법

컨텐츠 정보

  • 조회 325 (작성일 )

본문

블로그에 대한 댓글 섹션을 갖고 싶었지만 높은 비용과 유지 관리 솔루션에 압도 당했습니까? 

Firebase가 구세주가 될 수 있습니다. 이 가이드에서는 Firebase의 기본 사항을 배우면서 Firebase로 블로그에 댓글 섹션을 추가하는 방법을 알아 봅니다.


https://www.smashingmagazine.com/2020/08/comment-system-firebase/


댓글 섹션은 커뮤니티를 구축하는 좋은 방법입니다.


귀하의 블로그. 최근에 블로깅을 시작했을 때 댓글 섹션을 추가 할 생각을 했습니다. 

하지만 쉽지 않았습니다. Disqus 및 Commento와 같은 호스팅 된 댓글 시스템에는 고유 한 문제가 있습니다.

  • 그들은 귀하의 데이터를 소유합니다.
  • 그들은 자유롭지 않습니다.
  • 많이 사용자 지정할 수 없습니다.

그래서 나만의 댓글 시스템을 구축하기로 결정했습니다. Firebase는 백엔드 서버 실행에 대한 완벽한 호스팅 대안처럼 보였습니다.


우선, 자신 만의 데이터베이스를 갖는 모든 이점을 얻을 수 있습니다. 데이터를 제어하고 원하는 대로 구조화 할 수 있습니다. 둘째, 백엔드 서버를 설정할 필요가 없습니다. 프런트 엔드에서 쉽게 제어 할 수 있습니다. 백엔드의 번거로움이 없는 호스트 시스템이라는 두 가지 장점을 모두 갖춘 것과 같습니다.


이 게시물에서는 그것이 우리가 할 일입니다. 정적 사이트 생성기인 Gatsby로 Firebase를 설정하는 방법을 배웁니다. 그러나 이 원칙은 모든 정적 사이트 생성기에 적용될 수 있습니다.


Firebase 란? 


Firebase는 데이터베이스, 호스팅, 클라우드 기능, 인증, 분석, 저장소와 같은 앱 개발자를 위한 도구를 제공하는 백엔드 서비스입니다.


Cloud Firestore (Firebase의 데이터베이스)는 이 프로젝트에 사용할 기능입니다. NoSQL 데이터베이스입니다. 즉, 행, 열, 테이블이 있는 SQL 데이터베이스처럼 구조화되지 않았습니다. 큰 JSON 트리로 생각할 수 있습니다.


프로젝트 소개 


GitHub에서 저장소를 복제하거나 다운로드하여 프로젝트를 초기화하겠습니다.


진행 과정에서 변경 사항을 쉽게 추적 할 수 있도록 모든 단계에 대해 두 개의 브랜치를 만들었습니다 (시작과 끝에 하나씩).


다음 명령을 사용하여 프로젝트를 실행 해 보겠습니다.


gatsby develop


브라우저에서 프로젝트를 열면 기본 블로그의 뼈대를 볼 수 있습니다.


Basic blog 


댓글 섹션이 작동하지 않습니다. 단순히 샘플 댓글을 로드하고 댓글이 제출되면 세부 정보를 콘솔에 기록합니다.


우리의 주요 임무는 코멘트 섹션을 작동 시키는 것입니다.


댓글 섹션의 작동 방식 


무엇이든 하기 전에 코멘트 섹션의 코드가 어떻게 작동하는지 이해합시다.


네 가지 구성 요소가 주석 섹션을 처리합니다.

  • blog-post.js
  • Comments.js
  • CommentForm.js
  • Comment.js

먼저 게시물에 대한 댓글을 식별해야 합니다. 각 블로그 게시물에 대해 고유 한 ID를 만들거나 항상 고유 한 슬러그를 사용할 수 있습니다.


blog-post.js 파일은 모든 블로그 게시물의 레이아웃 구성 요소입니다. 블로그 게시물의 슬러그를 얻기 위한 완벽한 진입 점입니다. 이는 GraphQL 쿼리를 사용하여 수행됩니다.


export const query = graphql`
    query($slug: String!) {
        markdownRemark(fields: { slug: { eq: $slug } }) {
            html
            frontmatter {
                title
            }
            fields {
                slug
            }
        }
    }
`

Comments.js 구성 요소로 보내기 전에 substring() 메서드를 사용하여 Gatsby가 슬러그에 추가하는 후행 슬래시 (/)를 제거해 보겠습니다.


const slug = post.fields.slug.substring(1, post.fields.slug.length - 1)

return (
    <Layout>
        <div className="container">
            <h1>{post.frontmatter.title}</h1>
            <div dangerouslySetInnerHTML={{ __html: post.html }} />
            <Comments comments={comments} slug={slug} />
        </div>
    </Layout>
    )
 }


Comments.js 구성 요소는 각 주석을 매핑하고 해당 데이터를 모든 응답과 함께 Comment.js로 전달합니다. 이 프로젝트를 위해 저는 코멘트 시스템을 한 단계 더 깊게 하기로 결정했습니다.


구성 요소는 또한 CommentForm.js를 로드하여 최상위 주석을 캡처합니다.


const Comments = ({ comments, slug }) => {
    return (
        <div>
            <h2>Join the discussion</h2>
            <CommentForm slug={slug} />
            <CommentList>
                {comments.length > 0 &&
                    comments
                        .filter(comment => !comment.pId)
                        .map(comment => {
                            let child
                            if (comment.id) {
                                child = comments.find(c => comment.id === c.pId)
                            }
                            return (
                                <Comment
                                    key={comment.id}
                                    child={child}
                                    comment={comment}
                                    slug={slug}
                                />
                            )
                        })}
                    </CommentList>
                </div>
            )
        }


CommentForm.js로 이동하겠습니다. 이 파일은 간단하며 주석 양식을 렌더링하고 제출을 처리합니다. 제출 방법은 단순히 세부 정보를 콘솔에 기록합니다.


const handleCommentSubmission = async e => {
    e. preventDefault()
        let comment = {
            name: name,
            content: content,
            pId: parentId ∣∣ null,
            time: new Date(),
        }
        setName("")
        setContent("")
        console.log(comment)
    }


Comment.js 파일에는 많은 일이 있습니다. 더 작은 조각으로 나누겠습니다.


첫째, 주석을 렌더링 하는 SingleComment 구성 요소가 있습니다.


멋진 아바타를 얻기 위해 Lovely API를 사용하고 있습니다. Moment.js 라이브러리는 사람이 읽을 수 있는 형식으로 시간을 렌더링 하는 데 사용됩니다.


const SingleComment = ({ comment }) => (
    <div>
        <div className="flex-container">
            <div className="flex">
                <img
                    src="https://api.adorable.io/avazars/65/abott@adorable.png"
                    alt="Avatar"
                />
            </div>
            <div className="flex">
                <p className="comment-author">
                    {comment.name} <span>says</span>
                </p>
                {comment.time} &&(<time>(moment(comment.time.toDate()).calendar()}</time>)}
            </div>
        </div>
        </p>{comment.content}</p>
    </div>
)


파일의 다음은 Comment 컴포넌트입니다. 이 구성 요소는 자식 주석이 전달 된 경우 자식 주석을 표시합니다. 그렇지 않으면 "답장"단추 또는 "응답 취소"단추를 클릭하여 켜고 끌 수 있는 응답 상자를 렌더링합니다.


const Comment = ({ comment, child, slug }) => {
    const [showReplyBox, setShowReplyBox] = useState(false)
    return (
        <CommentBox>
            <SingleComment comment={comment} />
            {child && (
                <CommentBox child className=comment-reply">
                    <SingleComment comment={child} />
                </CommentBox>
            )}
            {!child && (
                <div>
                    {showReplyBox ? (
                        <div>
                            <button
                                className="btn bare"
                                onClick={() => setShowReplyBoy(false)}
                            >
                                Cancel Reply
                            </button>
                            <CommentForm parentId={comment.id} slug={slug} />
                        </div>
                    ) : (
                        <button className="btn bare" onClick={() => setShowReplyBox(true)}>
                            Reply
                        </button>
                    )}
                </div>
            )}
        </div>
    )}
</CommentBox>


이제 개요를 얻었으므로 댓글 작성 단계를 살펴 보겠습니다.


1. Firebase 추가 


먼저 프로젝트에 Firebase를 설정하겠습니다.


가입하여 시작하십시오. Firebase로 이동하여 Google 계정에 가입하세요. 없는 경우 "시작하기"를 클릭합니다.


새 프로젝트를 추가하려면 "프로젝트 추가"를 클릭하십시오. 프로젝트 이름을 추가하고 "프로젝트 만들기"를 클릭합니다.


Initialize Firebase 


프로젝트를 만든 후에는 Cloud Firestore를 설정해야 합니다.


왼쪽 메뉴에서 "데이터베이스"를 클릭합니다. 'Cloud Firestore'라는 페이지가 열리면 '데이터베이스 만들기'를 클릭하여 새 Cloud Firestore 데이터베이스를 만듭니다.


Cloud Firestore 


팝업이 나타나면 "테스트 모드에서 시작"을 선택합니다. 다음으로 가장 가까운 Cloud Firestore 위치를 선택합니다.


Firestore test mode 


이와 같은 페이지가 표시되면 Cloud Firestore 데이터베이스가 성공적으로 생성 된 것입니다.


Firestore dashboard 


응용 프로그램에 대한 논리를 설정하여 완료하겠습니다. 애플리케이션으로 돌아가 Firebase를 설치합니다.


yarn add firebase


루트 디렉터리에 새 파일 firebase.js를 추가합니다. 이 내용을 붙여 넣으십시오.


import firebase from "firebase/app"
import "firebase/firestore"

var firebaseConfig = 'yourFirebaseConfig'

firebase.initializeApp(firebaseConfig)

export const firestore = firebase.firestore()

export default firebase


yourFirebaseConfig를 프로젝트 용으로 교체해야 합니다. 이를 찾으려면 Firebase 앱에서 '프로젝트 개요'옆에 있는 톱니 바퀴 아이콘을 클릭하세요.


Project settings 


설정 페이지가 열립니다. 앱의 부제목 아래에서 다음과 같은 웹 아이콘을 클릭합니다.


Project installation 


팝업이 열립니다. "앱 닉네임"필드에 이름을 입력하고 "앱 등록"을 클릭합니다. 그러면 firebaseConfig 객체가 제공됩니다.


<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.15.5/firebase-app.js"></script>

<!-- TODO: Add SDKs for Firebase products that you want to use
    https://firebase.google.com/docs/web/setup#available-libraries -->

<script>
    // Your web app’s Firebase configuration
    var firebaseConfig = {

    ...

    };
    // Initialize Firebase
    firbase.initializeApp(firebaseConfig);
</script>


firebaseConfig 객체의 콘텐츠만 복사하여 firebase.js 파일에 붙여 넣습니다.


FIREBASE API 키를 노출해도 괜찮습니까? 


예. Google 엔지니어가 말했 듯이 API 키를 노출하는 것은 괜찮습니다.


API 키의 유일한 목적은 Google의 데이터베이스로 프로젝트를 식별하는 것입니다. Cloud Firestore에 대해 강력한 보안 규칙을 설정했다면 누군가가 API 키를 가져와도 걱정할 필요가 없습니다.


마지막 섹션에서 보안 규칙에 대해 이야기하겠습니다.


지금은 테스트 모드에서 Firestore를 실행하고 있으므로 API 키를 공개해서는 안됩니다.


FIRESTORE를 사용하는 방법? 


다음 두 가지 유형 중 하나로 데이터를 저장할 수 있습니다.


  • collection
    컬렉션에는 문서가 포함됩니다. 문서의 배열과 같습니다.
  • document
    문서에는 필드-값 쌍의 데이터가 포함됩니다.

컬렉션에는 문서 만 포함될 수 있으며 다른 컬렉션은 포함되지 않을 수 있습니다. 그러나 문서에는 다른 컬렉션이 포함될 수 있습니다.


즉, 컬렉션 내에 컬렉션을 저장하려면 다음과 같이 컬렉션을 문서에 저장하고 해당 문서를 컬렉션에 저장합니다.


{collection-1}/{document}/{collection-2}


데이터를 구조화하는 방법은 무엇입니까? 


Cloud Firestore는 본질적으로 계층 적이므로 사람들은 다음과 같은 데이터를 저장하는 경향이 있습니다.


blog/{blog-post-1}/content/comments/{comment-1}


그러나 이러한 방식으로 데이터를 저장하면 종종 문제가 발생합니다.


댓글을 받고 싶다고 가정 해보세요. 블로그 컬렉션 깊숙한 곳에 저장된 댓글을 찾아야 합니다. 이렇게 하면 코드에서 오류가 발생하기 쉽습니다. Chris Esplin은 하위 컬렉션을 사용하지 않는 것이 좋습니다.


데이터를 평면화 된 개체로 저장하는 것이 좋습니다.


blog-posts/{blog-post-1}
comments/{comment-1}

이렇게 하면 데이터를 쉽게 얻고 보낼 수 있습니다.


FIRESTORE에서 데이터를 얻는 방법은 무엇입니까? 


데이터를 얻기 위해 Firebase는 두 가지 방법을 제공합니다.


  • get()
    콘텐츠를 한 번 가져 오기 위한 것입니다.
  • onSnapshot()
    이 방법은 데이터를 보낸 다음 구독을 취소하지 않는 한 계속 업데이트를 보냅니다.

FIRESTORE에 데이터를 보내는 방법은 무엇입니까?


데이터를 가져 오는 것과 마찬가지로 Firebase에는 데이터를 저장하는 두 가지 방법이 있습니다.

  • set()
    문서의 ID를 지정하는 데 사용됩니다.
  • add()
    자동 ID로 문서를 만드는 데 사용됩니다.

알아 두어야 할 부분이 많았습니다. 하지만 걱정하지 마세요. 프로젝트에 도달하면 이러한 개념을 다시 살펴볼 것입니다.


2. 샘플 날짜 생성 


다음 단계는 쿼리 할 샘플 데이터를 만드는 것입니다. Firebase로 이동해 보겠습니다.


Cloud Firestore로 이동합니다. "컬렉션 시작"을 클릭합니다. "컬렉션 ID"에 대한 설명을 입력하고 "다음"을 클릭합니다.


Add collection 


"문서 ID"의 경우 "자동 ID"를 클릭합니다. 다음 데이터를 입력하고“저장”을 클릭합니다.


Add document 


데이터를 입력하는 동안 '필드'및 '유형'이 위 스크린 샷과 일치하는지 확인하세요. 그런 다음 "저장"을 클릭합니다.


이것이 Firestore에서 수동으로 댓글을 추가하는 방법입니다. 이 과정은 번거로워 보이지만 걱정하지 마세요. 이제부터는 앱에서 댓글 추가를 처리합니다.


이 시점에서 데이터베이스는 comments / {comment}와 같습니다.


3. 코멘트 데이터 얻기 


샘플 데이터를 쿼리 할 준비가 되었습니다. 블로그에 대한 데이터를 가져 와서 시작하겠습니다.


blog-post.js로 이동하고 방금 만든 Firebase 파일에서 Firestore를 가져옵니다.


import {firestore} from "../../firebase.js"


쿼리를 위해 React의 useEffect 후크를 사용합니다. 아직 가져 오지 않았다면 가져 오겠습니다.


useEffect(() => {
    firestore
      .collection(`comments`)
      .onSnapshot(snapshot => {
        const posts = snapshot.docs
        .filter(doc => doc.data().slug === slug)
        .map(doc => {
          return { id: doc.id, ...doc.data() }
        })
        setComments(posts)
      })
}, [slug])


데이터를 가져 오는 데 사용되는 방법은 onSnapshot입니다. 이는 우리가 상태 변화를 듣고 싶기 때문입니다. 따라서 사용자가 브라우저를 새로 고칠 필요 없이 주석이 업데이트 됩니다.


필터 및 맵 방법을 사용하여 슬러그가 현재 슬러그와 일치하는 주석을 찾았습니다.


마지막으로 생각해야 할 것은 정리입니다. onSnapshot이 계속 업데이트를 전송하기 때문에 이로 인해 애플리케이션에서 메모리 누수가 발생할 수 있습니다. 다행히 Firebase는 깔끔한 수정을 제공합니다.


useEffect(() => {
    const cleanUp = firestore
      .doc(`comments/${slug}`)
      .collection("comments")
      .onSnapshot(snapshot => {
        const posts = snapshot.docs.map(doc => {
          return { id: doc.id, ...doc.data() }
        })
        setComments(posts)
      })
    return () => cleanUp()
  }, [slug])


완료되면 gatsby develop을 실행하여 변경 사항을 확인합니다. 이제 Firebase에서 데이터를 가져 오는 댓글 섹션을 볼 수 있습니다.


Getting Firestore data 


댓글을 저장해 보겠습니다.


4. 댓글 저장 


주석을 저장하려면 CommentForm.js 파일로 이동하십시오. Firestore도 이 파일로 가져 오겠습니다.


import { firestore } from "../../firebase.js"

Firebase에 댓글을 저장하기 위해 add() 메소드를 사용합니다. Firestore에서 자동 ID로 문서를 생성하기를 원하기 때문입니다.


handleCommentSubmission 메소드에서 해보겠습니다.


firestore
.collection(`comments`)
.add(comment)
.catch(err => {
   console.error('error adding comment: ', err)
 })

먼저, 주석 컬렉션에 대한 참조를 얻은 다음 주석을 추가합니다. 또한 주석을 추가하는 동안 오류를 포착하기 위해 catch 메서드를 사용하고 있습니다.


이 시점에서 브라우저를 열면 댓글 섹션이 작동하는 것을 볼 수 있습니다. 새 댓글을 추가하고 답글을 게시 할 수 있습니다. 더 놀라운 것은 페이지를 새로 고치지 않고도 모든 것이 작동한다는 것입니다.


Storing comment 


Firestore에서 데이터를 저장하고 있는지 확인할 수도 있습니다.


Stored data in Firestore 


마지막으로 Firebase에서 중요한 사항 중 하나 인 보안 규칙에 대해 이야기하겠습니다.


5. 보안 규칙 강화 


지금까지 테스트 모드에서 Cloud Firestore를 실행했습니다. 즉, URL에 대한 액세스 권한이 있는 사람은 누구나 데이터베이스를 추가하고 읽을 수 있습니다. 무섭네요.


이를 해결하기 위해 Firebase는 보안 규칙을 제공합니다. Cloud Firestore에서 데이터베이스 패턴을 만들고 특정 활동을 제한 할 수 있습니다.


두 가지 기본 작업 (읽기 및 쓰기) 외에도 Firebase는 가져 오기, 나열, 만들기, 업데이트 및 삭제와 같은 보다 세분화 된 작업을 제공합니다.


읽기 작업은 다음과 같이 분류 할 수 있습니다.


  • get
    단일 문서를 가져옵니다.
  • list
    문서 또는 컬렉션 목록을 가져옵니다.

쓰기 작업은 다음과 같이 나눌 수 있습니다.


  • create
    새 문서를 만듭니다.
  • update
    기존 문서를 업데이트합니다.
  • delete
    문서를 삭제하십시오.

애플리케이션을 보호하려면 Cloud Firestore로 돌아 가세요. "규칙"에서 다음을 입력하십시오.


service cloud.firestore {
    match /databases/{database}/documents {
    match /comments/{id=**} {
        allow read, create;
    }
    }
}

첫 번째 줄에서는 서비스를 정의합니다.이 경우에는 Firestore입니다. 다음 줄은 Firebase에 댓글 컬렉션 내의 모든 내용을 읽고 생성 할 수 있음을 알려줍니다.


이것을 사용한 경우 :


allow read, write;


… 이는 사용자가 기존 댓글을 업데이트하고 삭제할 수 있다는 것을 의미합니다.


Firebase의 보안 규칙은 매우 강력하여 특정 데이터, 활동은 물론 사용자까지 제한 할 수 있습니다.


나만의 댓글 섹션 구축 


축하합니다! Firebase의 강력한 기능을 방금 보셨습니다. 안전하고 빠른 애플리케이션을 구축 할 수 있는 훌륭한 도구입니다.


매우 간단한 댓글 섹션을 만들었습니다. 하지만 더 이상의 가능성을 탐색하는 데에는 방해가 되지 않습니다.


  • 프로필 사진을 추가하고 Firebase 용 Cloud Storage에 저장합니다.
  • Firebase를 사용하여 사용자가 계정을 만들고 Firebase 인증을 사용하여 인증 할 수 있도록 합니다.
  • Firebase를 사용하여 인라인 Medium과 유사한 댓글을 작성하세요.

시작하는 가장 좋은 방법은 Firestore의 문서로 이동하는 것입니다.


마지막으로 아래 댓글 섹션으로 이동하여 Firebase를 사용하여 댓글 섹션을 구축 한 경험에 대해 논의하겠습니다.