构建 React & Firebase 博客网站:第 2 部分

2025-06-08

构建 React & Firebase 博客网站:第 2 部分

这篇文章最初发表在我的个人博客网站上

欢迎回来!这是本系列文章的第二篇,将教您如何使用 React 和 Firebase 构建博客网站。如果您还没有阅读本系列的第一篇文章,我建议您阅读一下。我为这篇文章提供了初始代码,但您还需要完成上一篇文章中的以下步骤才能使用它:

  • 步骤 1:注册 Firebase(如果您还没有帐户)
  • 第 2 步:创建项目
  • 步骤 5:向数据库添加数据

公平警告:由于这篇文章是基于第 1 部分撰写的,因此如果您密切关注本文,则假定您已经阅读过该文章。

目录

  1. 克隆(第 2 部分)启动代码 [可选]
  2. 添加创建帖子的页面
  3. 输入描述帖子的内容
  4. 编写创建函数

1. 克隆(第 2 部分)启动代码 [可选]

如果您已成功完成第 1 部分,请跳过此步骤。否则,您可以通过在终端中运行以下命令开始克隆代码:

git clone https://github.com/ashleemboyer/react-firebase-blog-starter-part-2.git
Enter fullscreen mode Exit fullscreen mode

在继续之前,您需要更改一个文件:src/firebase.js。如果打开它,您将看到以下config常量:

const config = {
  apiKey: "<YOUR-API-KEY>",
  authDomain: "<YOUR-AUTH-DOMAIN>",
  databaseURL: "<YOUR-DATABASE-URL>",
  projectId: "<YOUR-PROJECT-ID>",
  storageBucket: "<YOUR-STORAGE-BUCKET>",
  messagingSenderId: "<YOUR-MESSAGE-SENDER-ID>",
  appId: "<YOUR-APP-ID>"
};
Enter fullscreen mode Exit fullscreen mode

常量中的属性用于将您的应用连接到 Firebase 项目。要查找这些值,请使用Firebase 控制台左侧边栏中的齿轮图标 ,转到您的项目设置。向下滚动到“您的应用”下的“Firebase SDK 代码段”,然后从它们调用的内容中复制属性firebaseConfig。用这些值替换常量中的属性config

现在您可以运行npm installnpm run start在浏览器中查看您的项目。

2. 添加创建帖子的页面

您不必先执行此步骤。我只是按照首字母缩略词的顺序编写这些步骤。

要开始实现“创建帖子”功能,我们首先要创建一个用于创建帖子的页面。create.js在 中添加一个文件src/pages。为了确保一切正常运行,我们暂时将其保持在极简状态。

当您采取渐进的步骤并在整个过程中检查您的工作时,开发代码是最容易的。

我们的Create组件现在会发出友好的“你好”。

import React from "react";

const Create = () => {
  return <h1>Hello, from Create!</h1>;
};

export default Create;
Enter fullscreen mode Exit fullscreen mode

尝试导航到该/create页面。呃,哦……找不到该页面?

404 页面。

Route别担心!我们只需要在 中为新页面添加一个src/App.js。首先为组件添加一个导入Create

import Create from "./pages/create";
Enter fullscreen mode Exit fullscreen mode

然后,Route在路径下方添加以下内容/

<Route path="/create" component={Create} />
Enter fullscreen mode Exit fullscreen mode

新的创建页面现在应该可以正常工作了!

创建页面。

3. 输入描述帖子的内容

现在,让我们思考一下实时数据库中的数据结构。以下每个属性都是我们用来描述博客文章的:

  • 标题
  • 蛞蝓
  • 日期
  • 封面图片
  • 封面图片Alt
  • 内容

考虑以下两个问题:我们需要为哪些属性创建<input>for?哪些属性我们可以通过一些额外的代码自动生成?嗯……

如果我要为客户制作这个博客网站,我会自动生成slugdate。日期的自动生成并不难,但 slug 可能因为标点符号而变得复杂。我们这里不打算处理这个问题,但您可以自行尝试!此外,我可能会为 提供一个文件上传输入框coverImage,但这也比我这篇博文想要描述的要复杂一些。

所以,date是我们唯一要自动生成的。除了 之外,所有输入都会有content, 会得到<textarea>。让我们把所有这些输入都添加到我们的组件中,并使用 处理它们的值useState。你的src/pages/create.js文件应该如下所示:

如果你觉得这代码冗余了,那就太好了!(抱歉😅)我们会在“后续更新”的帖子里解决这个问题。

import React, { useState } from "react";

const labelStyles = {
  display: "block",
  marginBottom: 4
};

const inputStyles = {
  width: "100%",
  height: "2rem",
  lineHeight: "2rem",
  verticalAlign: "middle",
  fontSize: "1rem",
  marginBottom: "1.5rem",
  padding: "0 0.25rem"
};

const Create = () => {
  const [title, setTitle] = useState("");
  const [slug, setSlug] = useState("");
  const [coverImage, setCoverImage] = useState("");
  const [coverImageAlt, setCoverImageAlt] = useState("");
  const [content, setContent] = useState("");

  const createPost = () => {
    console.log({ title, slug, coverImage, coverImageAlt, content });
  };

  return (
    <>
      <h1>Create a new post</h1>
      <section style={{ margin: "2rem 0" }}>
        <label style={labelStyles} htmlFor="title-field">
          Title
        </label>
        <input
          style={inputStyles}
          id="title-field"
          type="text"
          value={title}
          onChange={({ target: { value } }) => {
            setTitle(value);
          }}
        />

        <label style={labelStyles} htmlFor="slug-field">
          Slug
        </label>
        <input
          style={inputStyles}
          id="slug-field"
          type="text"
          value={slug}
          onChange={({ target: { value } }) => {
            setSlug(value);
          }}
        />

        <label style={labelStyles} htmlFor="cover-image-field">
          Cover image
        </label>
        <input
          style={inputStyles}
          id="cover-image-field"
          type="text"
          value={coverImage}
          onChange={({ target: { value } }) => {
            setCoverImage(value);
          }}
        />

        <label style={labelStyles} htmlFor="cover-image-alt-field">
          Cover image alt
        </label>
        <input
          style={inputStyles}
          id="cover-image-alt-field"
          type="text"
          value={coverImageAlt}
          onChange={({ target: { value } }) => {
            setCoverImageAlt(value);
          }}
        />

        <label style={labelStyles} htmlFor="content-field">
          Content
        </label>
        <textarea
          style={{ ...inputStyles, height: 200, verticalAlign: "top" }}
          id="content"
          type="text"
          value={content}
          onChange={({ target: { value } }) => {
            setContent(value);
          }}
        />
        <div style={{ textAlign: "right" }}>
          <button
            style={{
              border: "none",
              color: "#fff",
              backgroundColor: "#039be5",
              borderRadius: "4px",
              padding: "8px 12px",
              fontSize: "0.9rem"
            }}
            onClick={createPost}
          >
            Create
          </button>
        </div>
      </section>
    </>
  );
};

export default Create;
Enter fullscreen mode Exit fullscreen mode

您的页面现在看起来应该是这样的:

带有输入的创建页面。

简单填写所有这些字段,看看点击“创建”按钮后会发生什么!你的控制台打开了吗?然后你应该会看到一个对象,里面打印了所有输入的值。我的控制台如下所示(点击展开):

创建页面,其中填写了输入,并且其值记录到控制台。

4. 编写创建函数

太棒了!这就是我所说的代码增量修改。一步一步来。让我们进入激动人心的部分!我们要将一些内容发送回数据库。首先,我们需要从 导入我们的getFirebase函数src/firebase.js

import { getFirebase } from "../firebase";
Enter fullscreen mode Exit fullscreen mode

现在,添加generateDate()函数,更新createPost函数,并historyCreate组件参数中解构 prop:

const generateDate = () => {
  const now = new Date();
  const options = { month: "long", day: "numeric", year: "numeric" };

  const year = now.getFullYear();
  let month = now.getMonth() + 1;
  if (month < 10) {
    month = `0${month}`; // prepend with a 0
  }

  const day = now.getDate();
  if (day < 10) {
    day = `0${day}`; // prepend with a 0
  }

  return {
    formatted: `${year}-${month}-${day}`,             // used for sorting
    pretty: now.toLocaleDateString("en-US", options)  // used for displaying
  };
};
Enter fullscreen mode Exit fullscreen mode
const createPost = () => {
  const date = generateDate();
  const newPost = {
    title,
    dateFormatted: date.formatted,
    datePretty: date.pretty,
    slug,
    coverImage,
    coverImageAlt,
    content
  };
  getFirebase()
    .database()
    .ref()
    .child(`posts/${slug}`)
    .set(newPost)
    .then(() => history.push(`/`));
};
Enter fullscreen mode Exit fullscreen mode
const Create = ({ history }) => {
  ...
}
Enter fullscreen mode Exit fullscreen mode

像我们几分钟前所做的那样填写您的输入,单击“创建帖子”,您将被带到主页,您的新帖子位于最顶部!

主页上首先列出的是新帖子。

5.总结

呼!我以为我们能在一篇文章里讲完所有 4 个 CRUD 函数,但内容太多了。下一篇文章我们会继续讲解身份验证的探索之旅。目前为止,做得不错。💪

如果遇到任何问题或疑问,请给我发邮件在推特上私信我!回头见!😊


你知道我有一份新闻通讯吗?📬

如果您想在我发布新博客文章或发布重大项目公告时收到通知,请访问https://ashleemboyer.com/newsletter

鏂囩珷鏉ユ簮锛�https://dev.to/ashleemboyer/build-a-react-firebase-blog-site-part-2-2inm
PREV
亲爱的妇女和女孩们
NEXT
目标是永不停止学习 AWS 安全 LIVE!