如何使用 Firebase 构建自己的评论系统

已发表: 2022-03-10
快速总结↬曾经想为您的博客设置评论部分,但被高昂的成本和维护解决方案所淹没? Firebase 可以成为您的救星。 在本指南中,我们将学习如何使用 Firebase 在您的博客中添加评论部分,同时学习 Firebase 的基础知识。

评论部分是为您的博客建立社区的好方法。 最近开始写博客的时候,我想添加一个评论部分。 然而,这并不容易。 托管评论系统,例如 Disqus 和 Commento,都有自己的一系列问题:

  • 他们拥有您的数据。
  • 他们不是免费的。
  • 您不能对它们进行太多自定义。

所以,我决定建立自己的评论系统。 Firebase 似乎是运行后端服务器的完美托管替代方案。

首先,您可以获得拥有自己的数据库的所有好处:您可以控制数据,并且可以根据需要对其进行结构化。 其次,您不需要设置后端服务器。 您可以从前端轻松控制它。 这就像两全其美:一个没有后端麻烦的托管系统。

在这篇文章中,这就是我们要做的。 我们将学习如何使用静态站点生成器 Gatsby 设置 Firebase。 但是这些原理可以应用于任何静态站点生成器。

让我们潜入吧!

什么是 Firebase?

Firebase 是一种后端即服务,它为应用程序开发人员提供工具,例如数据库、托管、云功能、身份验证、分析和存储。

Cloud Firestore(Firebase 的数据库)是我们将用于此项目的功能。 它是一个 NoSQL 数据库。 这意味着它的结构不像具有行、列和表的 SQL 数据库。 您可以将其视为一棵大型 JSON 树。

项目介绍

让我们通过从 GitHub 克隆或下载存储库来初始化项目。

我为每个步骤创建了两个分支(一个在开头,一个在结尾),以便您更轻松地跟踪我们进行的更改。

让我们使用以下命令运行项目:

 gatsby develop

如果您在浏览器中打开该项目,您将看到一个基本博客的基本内容。

基本博客
(大预览)

评论部分不工作。 它只是加载一个示例评论,并且在提交评论后,它将详细信息记录到控制台。

我们的主要任务是让评论部分正常工作。

跳跃后更多! 继续往下看↓

评论部分的工作原理

在做任何事情之前,让我们了解一下注释部分的代码是如何工作的。

四个组件正在处理评论部分:

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

首先,我们需要识别帖子的评论。 这可以通过为每篇博客文章创建一个唯一的 ID 来完成,或者我们可以使用 slug,它始终是唯一的。

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 添加到 slug 的尾部斜杠 ( / )。

 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组件,它呈现评论。

我正在使用 Adorable API 来获得一个很酷的头像。 Moment.js 库用于以人类可读的格式呈现时间。

 const SingleComment = ({ comment }) => ( <div> <div className="flex-container"> <div className="flex"> <img src="https://api.adorable.io/avazars/65/[email protected]" 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,并注册一个 Google 帐户。 如果您还没有,请单击“开始”。

单击“添加项目”以添加新项目。 为您的项目添加名称,然后单击“创建项目”。

初始化 Firebase
(大预览)

创建项目后,我们需要设置 Cloud Firestore。

在左侧菜单中,单击“数据库”。 页面打开后显示“Cloud Firestore”,单击“创建数据库”以创建新的 Cloud Firestore 数据库。

云防火墙
(大预览)

出现弹出窗口时,选择“以测试模式启动”。 接下来,选择离您最近的 Cloud Firestore 位置。

Firestore 测试模式
(大预览)

一旦您看到这样的页面,就意味着您已经成功创建了 Cloud Firestore 数据库。

Firestore 仪表板
(大预览)

让我们通过设置应用程序的逻辑来完成。 返回应用程序并安装 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 应用程序中“项目概述”旁边的齿轮图标。

项目设置
(大预览)

这将打开设置页面。 在您的应用程序的副标题下,单击 Web 图标,如下所示:

项目安装
(大预览)

这将打开一个弹出窗口。 在“应用昵称”字段中,输入任意名称,然后单击“注册应用”。 这会给你的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-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”输入comments ,然后单击“下一步”。

添加收藏
(大预览)

对于“文档 ID”,单击“自动 ID。 输入以下数据,然后单击“保存”。

添加文档
(大预览)

输入数据时,请确保“字段”和“类型”与上面的屏幕截图相匹配。 然后,单击“保存”。

这就是您在 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 。 这是因为我们也想监听状态变化。 因此,评论将得到更新,而无需用户刷新浏览器。

我们使用filtermap方法来查找其 slug 与当前 slug 匹配的评论。

我们需要考虑的最后一件事是清理。 因为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 获取数据。

获取 Firestore 数据
(大预览)

让我们来存储评论。

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) })

首先,我们获取到comments 集合的引用,然后添加comment。 我们还使用catch方法在添加注释时捕获任何错误。

此时,如果您打开浏览器,您可以看到评论部分正常工作。 我们可以添加新评论,也可以发布回复。 更令人惊奇的是,无需我们刷新页面即可一切正常。

存储评论
(大预览)

您还可以检查 Firestore 以查看它是否正在存储数据。

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, comments集合中的任何内容都可以被读取和创建。

如果我们使用了这个:

 allow read, write;

…这意味着用户可以更新和删除我们不想要的现有评论。

Firebase 的安全规则非常强大,允许我们限制某些数据、活动甚至用户。

建立自己的评论部分

恭喜! 您刚刚看到了 Firebase 的强大功能。 它是构建安全和快速应用程序的绝佳工具。

我们建立了一个超级简单的评论部分。 但没有阻止您探索更多可能性:

  • 添加头像,并将其存储在 Cloud Storage for Firebase 中;
  • 使用 Firebase 允许用户创建帐户,并使用 Firebase 身份验证对其进行身份验证;
  • 使用 Firebase 创建类似于 Medium 的内联评论。

一个很好的开始方法是查看 Firestore 的文档。

最后,让我们转到下面的评论部分,讨论您使用 Firebase 构建评论部分的经验。

当然,在 Smashing Workshops 中,Smashing Cat 探索新的见解。

有用的前端和用户体验位,每周交付一次。

借助工具帮助您更好地完成工作。 通过电子邮件订阅并获取 Vitaly 的智能界面设计清单 PDF

在前端和用户体验上。 受到 190.000 人的信赖。