一、MERN 部署设置
欢迎来到面向初学者的 MERN 项目,在这里你将学习使用 MERN (MongoDB,Express,React,Node.js)框架构建令人敬畏的 web 应用。这种堆栈在创业领域有很高的需求,因为你可以用它来制作一个全功能的 web 应用。一个懂 HTML、CSS、React 的前端工程师,可以很快学会 Node.js 和 MongoDB,构建一个完全量产就绪的 web app。
在本书中,您将学习如何在 Heroku 中使用 Node.js 代码托管后端。前端站点使用 React 代码和 Firebase 托管。它还通过一个名为 MongoDB Atlas 的云数据库托管。在接下来的五章中,大多数主机设置都是相同的,所以在大多数章节中不会重复。
MERN 堆栈一览
在安装 Firebase 之前,让我们讨论一下 MERN 堆栈中涉及的基础技术。
-
MongoDB 是一个基于 NoSQL 数据库的开源文档。它不同于将数据存储在表中的传统关系数据库。它将数据存储在类似 JSON 的文档中。它具有高度的可扩展性和性能导向性,因此适合现代网络应用。
-
React 是最流行的开源 JavaScript 库,用于构建网站或 web 应用的前端或用户界面。它由脸书开发和维护。
-
Node.js 允许开发者使用 JavaScript 编写服务器端代码。它与前端的 React 或 Angular 以及数据库的 MongoDB 集成得非常好。
-
Express 是 Node.js 的一个框架,通过它可以创建 API 端点,这些端点是任何后端服务器端代码的基础。
Firebase 托管初始设置
你需要一个谷歌账户才能使用 Firebase。进入 https://firebase.google.com
,点击进入右上角的控制台。你必须登录你的谷歌账户,如图 1-1 所示。
图 1-1
Firebase 控制台标题
点击页面中的添加项目链接,如图 1-2 所示。
图 1-2
添加项目
在此页面中,将项目命名为 dating-app-mern ,然后点击继续按钮,如图 1-3 所示。请注意,这只是一个安装说明。你将在下一章开始构建应用。
图 1-3
应用名称
在下一页面中,点击创建项目按钮,如图 1-4 所示。
图 1-4
创建项目
创建项目需要一些时间,如图 1-5 所示。
图 1-5
项目已创建
MongoDB 设置
MongoDB 是您在云上使用的数据库。它也被称为 MongoDB Atlas。这比在本地机器上设置更容易操作。进入 www.mongodb.com
并登录或创建新账户。
创建新项目
登录后,您会看到类似于图 1-6 所示的屏幕。点击新建项目按钮。
图 1-6
MongoDB 新项目
将你的项目命名为 dating-app-mern ,然后点击下一步按钮,如图 1-7 所示。
图 1-7
项目名
在下一个屏幕上,点击创建项目按钮,如图 1-8 所示。
图 1-8
MongoDB 创建项目
在下一个屏幕上,点击建立集群按钮,如图 1-9 所示。
图 1-9
构建集群
在下一个屏幕上,选择自由层,如图 1-10 所示。
图 1-10
自由层
在下一个屏幕上,您需要选择要在其中创建数据库的 AWS 区域。(我选择孟买是因为我住在印度,这给了我低延迟。)之后,点击创建集群按钮,如图 1-11 所示。
图 1-11
选择区域
下一个屏幕显示集群已经创建,这需要时间。您可以返回并创建您的第一个 API 端点,如图 1-12 所示。
图 1-12
集群已创建
数据库用户和网络访问
在 MongoDB 中创建用户,点击数据库访问页签,然后点击添加新数据库用户按钮,如图 1-13 所示。
图 1-13
创建数据库用户
在下一个屏幕上,您需要输入用户名和密码,如图 1-14 所示。你必须记住这两点。接下来,向下滚动并点击添加用户按钮。
图 1-14
添加用户
接下来,进入网络访问选项卡,点击添加 IP 地址按钮,如图 1-15 所示。
图 1-15
网络存取
在弹出的窗口中,点击允许从任何地方访问按钮,然后点击确认按钮,如图 1-16 所示。
图 1-16
允许访问
接下来,返回到集群选项卡,点击连接按钮,弹出如图 1-17 所示的窗口。单击连接您的应用选项卡。
图 1-17
连接应用
点击复制按钮复制连接 URL,如图 1-18 所示。
图 1-18
连接字符串
将后端部署到 Heroku
完成后端代码后,进入 www.heroku.com
部署后端。登录你的 Heroku 账号,点击新建下拉菜单,然后点击新建 app 按钮,如图 1-19 所示。您也可以从命令行使用 Heroku CLI 来实现这一点,但这里不做介绍。
图 1-19
英雄库登录
接下来命名 app,点击创建 app 按钮,如图 1-20 所示。
图 1-20
Heroku app name
下一个屏幕显示了部署您的应用的所有命令,但是您需要 Heroku CLI。点击链接,按照说明将其安装到您的操作系统上,如图 1-21 所示。
图 1-21
希律王的指示
运行backend
文件夹中的heroku login
命令。系统会询问您是否有权限打开浏览器。此命令要求您按任意键在浏览器中打开。
图 1-22。
在这里,您可以使用您的凭证登录,如图 1-23 所示。
图 1-23
登录凭据
成功登录后,您会看到如图 1-24 所示的页面,您需要关闭该页面。
图 1-24
关闭弹出窗口
您需要将代码从本地机器推送到 Heroku 存储库。现在您已经登录到您的帐户,您可以运行以下命令来连接 Heroku Git。
heroku git:remote -a dating-mern-backend
接下来,让我们运行熟悉的git
命令来提交代码。Git 是一个跟踪文件变化的软件。这是软件开发中必须的。以下命令将代码添加到临时区域,然后提交代码。push
命令将其推送到远程 Heroku 服务器。
git add .
git commit -m "backend code complete"
git push heroku master
安装完成后,点击打开 app 按钮,进入部署站点,如图 1-25 所示。
图 1-25
打开后端应用
将前端部署到 Firebase
在前端项目完成之后(在下一章中),您可以在 Firebase 中部署它。转到frontend
文件夹,在终端中运行firebase login
命令。如果是第一次运行,将会打开一个弹出窗口。接下来,运行firebase init
命令。键入 Y 继续。
firebase login
firebase init
使用向下箭头键进入托管,如图 1-26 所示。按空格键选择它,然后按 Enter 键。
图 1-26
安装ˌ使成形
选择使用已有项目,如图 1-27 所示,按回车键。
图 1-27
现有项目
接下来选择正确的项目,在我这里是 dating-app-mern-453b1 ,如图 1-28 所示。
图 1-28
正确的项目
接下来选择公共目录,也就是build
。下面这个问题问的是一个单页 app 回答是。下一个问题是关于 GitHub 部署的;回答否,如图 1-29 所示。
图 1-29
建设
接下来,运行frontend
文件夹中的npm run build
以获得最佳的生产版本。最后一个命令,firebase deploy
,将项目部署到 Firebase。如果成功,该网站现在是活的,这将在接下来的章节中显示。
安装 Node.js 和 npm
如果您的系统上还没有安装 Node.js 和 npm(Node 包管理器),我们来看一下它们的安装。本书中的大部分代码都需要 Node.js 和 npm。React 前端代码也需要 Node.js,通过 npm,可以安装很多小型开源程序,为 React 和 Node.js 都增加了功能。
当您安装 Node.js 时,npm 也会自动安装在您的系统上。尽管 macOS 用户可以在互联网上找到类似的指南,但以下说明适用于基于 Windows 的系统。
在你的网页浏览器中,输入 https://nodejs.org/en/download/
,点击 Windows Installer,如图 1-30 所示。同样,它还会安装 npm。
图 1-30
Node.js installer(Node. js 安装程序)
默认情况下,下载的文件安装在您的下载文件夹中。点击它,然后点击运行按钮,如图 1-31 所示。
图 1-31
快动按钮
在 Node.js 安装弹出窗口中,点击下一步按钮,如图 1-32 所示。
图 1-32
Node.js 欢迎
点击接受最终用户许可协议,然后点击下一步按钮,如图 1-33 所示。
图 1-33
协议
接下来,我建议您使用图 1-34 所示的安装位置。
图 1-34
安装位置
向导要求您选择一个包。保持默认设置,如图 1-35 所示。
图 1-35
默认包
接下来点击复选框,然后点击下一个按钮,如图 1-36 所示。
图 1-36
属国
然后点击安装按钮,如图 1-37 所示。
图 1-37
安装
安装完成后,运行以下命令检查版本并验证一切正常。
node –v
npm -v
摘要
在这一章中,我们学习了创建 MERN(MongoDB,Express,ReactJS,NodeJS)项目的所有不同技术。我们还学习了如何在不同的环境中部署它们,我们将在接下来的章节中使用它们。
二、使用 MERN 开发约会应用
欢迎来到第二章,在这里你将使用 MERN (MongoDB,Express,React,Node.js)框架构建一个约会应用。后端托管在 Heroku,前端站点使用 Firebase 托管。项目中的图标来自 Material-UI。
该 web 应用功能简单,是第一个 MERN 堆栈项目。部署在 Firebase 中的成品 app 的截图如图 2-1 所示。所有数据都来自 MongoDB 数据库,API 端点设置在 Node.js 中。
图 2-1
完成的应用
让我们先回顾一下 React 前端,然后转到后端。打开您的终端并创建一个dating-app-mern
文件夹。在里面,使用 create-react-app 创建一个新的 app,名为 dating-app-frontend 。以下是完成此操作的命令。
mkdir dating-app-mern
cd dating-app-mern
npx create-react-app dating-app-frontend
Firebase 托管初始设置
由于前端站点是通过 Firebase 托管的,所以让我们在 create-react-app 创建 React app 的同时创建基本设置。按照第一章中相同的设置说明,我在 Firebase 控制台中创建了 dating-app-mern。
React 基本设置
返回 React 项目,将cd
返回到dating-app-frontend
目录。用npm start
启动 React 应用。
cd dating-app-frontend
npm start
接下来,让我们删除一些你不需要的文件。图 2-2 显示了该应用在 localhost 上的外观。
图 2-2
删除文件
让我们删除所有不必要的样板代码。index.js
文件应该如下所示。
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
App.js
只包含文字交友 App MERN 。来自App.css
文件的所有内容都已被删除。
import './App.css';
function App() {
return (
<div className="app">
<h1>Dating App MERN </h1>
</div>
);
}
export default App;
在index.css
中,更新 CSS,使margin: 0
位于顶部。
* {
margin: 0;
}
图 2-3 显示了该应用在 localhost 上的外观。
图 2-3
初始应用
创建标题组件
让我们创建一个标题组件。首先,你必须安装 Material-UI ( https://material-ui.com
),它提供了图标。根据 Material-UI 文档,您需要进行两次 npm 安装。通过dating-app-frontend
文件夹中的集成端子安装铁芯。
npm i @material-ui/core @material-ui/icons
接下来,在src
文件夹中创建一个components
文件夹。在components
文件夹中创建两个文件——Header.js
和Header.css—
。Header.js
有三样东西:一个人物图标、一个徽标和一个论坛图标。该徽标来自项目的公共目录,默认情况下包含 React 徽标。
以下是Header.js
文件的内容。
import React from 'react'
import './Header.css'
import PersonIcon from '@material-ui/icons/Person'
import IconButton from '@material-ui/core/IconButton'
import ForumIcon from '@material-ui/icons/Forum'
const Header = () => {
return (
<div className="header">
<IconButton>
<PersonIcon fontSize="large" className="header__icon" />
</IconButton>
<img className="header__logo" src="logo192.png" alt="header" />
<IconButton>
<ForumIcon fontSize="large" className="header__icon" />
</IconButton>
</div>
)
}
export default Header
在本地主机上的App.js
文件中包含Header
组件。更新后的代码用粗体标记。
import './App.css';
import Header from './components/Header';
function App() {
return (
<div className="app">
<Header />
</div>
);
}
export default App;
Header.css
文件包含以下内容,包括简单的样式,完成了头。
.header{
display: flex;
align-items: center;
justify-content: space-between;
z-index: 100;
border-bottom: 1px solid #f9f9f9;
}
.header__logo{
object-fit: contain;
height: 40px;
}
.header__icon{
padding: 20px;
}
图 2-4 显示了应用现在在 localhost 上的样子。
图 2-4
标题组件
创建约会卡组件
现在让我们来研究第二个部分。在components
文件夹中创建两个文件DatingCards.js
和DatingCards.css
。然后将DatingCards
组件包含在App.js
文件中。更新后的代码用粗体标记。
import './App.css';
import Header from './components/Header';
import DatingCards from './components/DatingCards';
function App() {
return (
<div className="app">
<Header />
< DatingCards />
</div>
);
}
export default App;
在继续之前,您需要安装一个react-tinder-card
包。该包具有提供滑动效果的功能。
npm i react-tinder-card
接下来,将内容放入DatingCards.js
。在这里,在一个people
状态变量中,您存储了四个人的姓名和图像。接下来,导入DatingCard
,并将其作为组件使用。这里,你使用react-tinder-card
文档中提到的道具。
需要swiped
和outOfFrame
功能。当遍历每个人时,使用imgUrl
背景图像并在h3
标签中显示姓名。
import React, { useState } from 'react'
import DatingCard from 'react-tinder-card'
import './DatingCards.css'
const DatingCards = () => {
const [people, setPeople] = useState([
{ name: "Random Guy", imgUrl: "https://images.unsplash.com/photo-1520409364224-63400afe26e5?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=658&q=80" },
{ name: "Another Guy", imgUrl: "https://images.unsplash.com/photo-1519085360753-af0119f7cbe7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=634&q=80" },
{ name: "Random Girl", imgUrl: "https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=634&q=80" },
{ name: "Another Girl", imgUrl: "https://images.unsplash.com/photo-1529626455594-4ff0802cfb7e?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=634&q=80" }
])
const swiped = (direction, nameToDelete) => {
console.log("receiving " + nameToDelete)
}
const outOfFrame = (name) => {
console.log(name + " left the screen!!")
}
return (
<div className="datingCards">
<div className="datingCards__container">
{people.map((person) => (
<DatingCard
className="swipe"
key={person.name}
preventSwipe={['up', 'down']}
onSwipe={(dir) => swiped(dir, person.name)}
onCardLeftScreen={() => outOfFrame(person.name)} >
<div style={{ backgroundImage: `url(${person.imgUrl})`}} className="card">
<h3>{person.name}</h3>
</div>
</DatingCard>
))}
</div>
</div>
)
}
export default DatingCards
Localhost 显示了四个“人”,如图 2-5 所示,但是您需要设计所有的样式。
图 2-5
所有人
在DatingCards.css
文件中添加第一个样式,并使datingCards__container
成为 flexbox。接下来,将每张卡片设计成包含图片和其他东西的样式。请注意,您正在为每张卡片设置position: relative
,这将使元素相对于自身偏移,并提供宽度和高度。
.datingCards__container{
display: flex;
justify-content: center;
margin-top: 10vh;
}
.card{
position: relative;
background-color: white;
width: 600px;
padding: 20px;
max-width: 85vw;
height: 50vh;
box-shadow: 0px 18px 53px 0px rgba(0, 0, 0, 0.3);
border-radius: 20px;
background-size: cover;
background-position: center;
}
图 2-6 显示了这在本地主机上的样子。
图 2-6
图像出现
让我们再添加三个样式,从这个 swipe 中可以得到一个 card 类中的类。使用position: absolute
创造滑动效果的魔力。在DatingCards.css
文件中添加以下内容。
.swipe{
position: absolute;
}
.cardContent{
width: 100%;
height: 100%;
}
.card h3{
position: absolute;
bottom: 0;
margin: 10px;
color: white;
}
前端基本完成,如图 2-7 所示。它包含右扫和左扫功能。除了包含滑动按钮的页脚之外,一切都完成了。
图 2-7
几乎完成
创建滑动按钮组件
现在让我们创建SwipeButtons
组件,它是页脚中的按钮。这些按钮增加了应用的风格。因为这是一个简单的应用,所以它们不会起作用。在components
文件夹中创建两个文件SwipeButtons.js
和SwipeButtons.css
。你还需要把它包含在App.js
文件中。
更新的内容用粗体标记。
import './App.css';
import Header from './components/Header';
import DatingCards from './components/DatingCards';
import SwipeButtons from './components/SwipeButtons';
function App() {
return (
<div className="app">
<Header />
< DatingCards />
< SwipeButtons />
</div>
);
}
export default App;
SwipeButtons.js
文件的内容很简单。有五个来自 Material-UI 的图标包裹在IconButton
里面。
import React from 'react'
import './SwipeButtons.css'
import ReplayIcon from '@material-ui/icons/Replay'
import CloseIcon from '@material-ui/icons/Close'
import StarRateIcon from '@material-ui/icons/StarRate'
import FavoriteIcon from '@material-ui/icons/Favorite'
import FlashOnIcon from '@material-ui/icons/FlashOn'
import IconButton from '@material-ui/core/IconButton'
const SwipeButtons = () => {
return (
<div className="swipeButtons">
<IconButton className="swipeButtons__repeat">
<ReplayIcon fontSize="large" />
</IconButton>
<IconButton className="swipeButtons__left">
<CloseIcon fontSize="large" />
</IconButton>
<IconButton className="swipeButtons__star">
<StarRateIcon fontSize="large" />
</IconButton>
<IconButton className="swipeButtons__right">
<FavoriteIcon fontSize="large" />
</IconButton>
<IconButton className="swipeButtons__lightning">
<FlashOnIcon fontSize="large" />
</IconButton>
</div>
)
}
export default SwipeButtons
接下来,在SwipeButtons.css
文件中设置按钮的样式。首先,设计swipeButtons
类的样式,并使用position: fixed
使其灵活。在一个固定的位置,一个元素保持附着在指定的位置(在这个例子中是底部),甚至当用户滚动时。您还设计了由包创建的MuiIconButton-root
类的样式。
在SwipeButtons.css
文件中,用不同的颜色设计每个按钮。
.swipeButtons{
position: fixed;
bottom: 10vh;
display: flex;
width: 100%;
justify-content: space-evenly;
}
.swipeButtons .MuiIconButton-root{
background-color: white;
box-shadow: 0px 10px 53px 0px rgba(0, 0, 0, 0.3) !important;
}
.swipeButtons__repeat{
padding: 3vw !important;
color: #f5b748 !important;
}
.swipeButtons__left{
padding: 3vw !important;
color: #ec5e6f !important;
}
.swipeButtons__star{
padding: 3vw !important;
color: #62b4f9 !important;
}
.swipeButtons__right{
padding: 3vw !important;
color: #76e2b3 !important;
}
.swipeButtons__lightning{
padding: 3vw !important;
color: #915dd1 !important;
}
图 2-8 显示了本地主机上的项目。
图 2-8
前端完成
初始后端设置
让我们从 Node.js 代码开始,转到后端。打开一个新的终端窗口,在根目录下创建一个新的dating-app-backend
文件夹。输入git init
,因为 Heroku 稍后需要它。
mkdir dating-app-backend
cd dating-app-backend
git init
接下来,通过在终端中输入npm init
命令来创建一个package.json
文件。你被问了几个问题;对于大多数情况,请按回车键。你可以输入一个描述和作者,但不是强制的。您通常可以在server.js
设置进入点,因为这是标准(见图 2-9 )。
图 2-9
后端初始设置
一旦package.json
被创建,你需要创建包含node_modules
的.gitignore
文件,因为你不想以后将node_modules
推送到 Heroku。以下是.gitignore
文件的内容。
node_modules
接下来,打开package.json.
行"type"
:
"module"
需要在 Node.js 中启用类似 React 的导入,这些模块被称为 ECMA 模块。带有 require 语句的初始模块称为 CommonJS 模块。你可以在 https://blog.logrocket.com/how-to-use-ecmascript-modules-with-node-js/
了解更多。
您还需要包含一个启动脚本来运行server.js
文件。更新的内容用粗体标记。
{
"name": "dating-app-backend",
"version": "1.0.0",
"description": "The dating app backend",
"main": "server.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "Nabendu Biswas",
"license": "ISC"
}
在开始之前,您需要安装两个软件包。打开终端,在dating-app-backend
文件夹中安装 Express 和 Mongoose。
npm i express mongoose
MongoDB 设置
MongoDB 的设置与第一章中描述的相同。你需要遵循它并创建一个名为的新项目。
在继续之前,将nodemon
安装在dating-app-backend
文件夹中。每当您对server.js
文件中的代码进行任何更改时,Node 服务器都会立即重启。
npm i nodemon
初始路线设置
让我们创建初始路由,它通常检查是否一切都设置正确。Node.js 中的 Express 包允许您创建路由,这是大多数互联网的工作方式。大多数后端语言,如 Node.js、Java,都提供了创建这些与数据库交互的路由的功能。初始路由不与数据库交互,只是在您使用 GET 请求访问它时返回一个文本。在dating-app-backend
文件夹中创建一个server.js
文件。在这里,您首先导入 Express 和 Mongoose 包。接下来,使用 Express 创建一个在端口 8001 上运行的port
变量。
第一个 API 端点是一个由app.get()
创建的简单 GET 请求,如果成功,它会显示 Hello TheWebDev 文本。
然后你用app.listen()
监听 8001 端口。
import express from 'express'
import mongoose from 'mongoose'
//App Config
const app = express()
const port = process.env.PORT || 8001
//Middleware
//DB Config
//API Endpoints
app.get("/", (req, res) => res.status(200).send("Hello TheWebDev"))
//Listener
app.listen(port, () => console.log(`Listening on localhost: ${port}`))
在终端中,键入 nodemon server.js 。可以看到监听 localhost: 8001 控制台日志。为了检查路线是否正常工作,转到http://localhost:8001/
查看终点文本(见图 2-10 )。
图 2-10
初始路线
数据库用户和网络访问
在 MongoDB 中,您需要创建一个数据库用户并提供网络访问。该过程与第一章中的过程相同。按照这些说明,获取用户凭证和连接 URL。
在server.js
中,创建一个connection_url
变量,并将 URL 粘贴到从 MongoDB 获得的字符串中。输入您之前保存的密码,并提供一个数据库名称。更新后的代码用粗体标记。
...
//App Config
const app = express()
const port = process.env.PORT || 8001
const connection_url = 'mongodb+srv://admin:yourpassword@cluster0.lggjc.mongodb.net/datingDB?retryWrites=true&w=majority'
//Middleware
//DB Config
mongoose.connect(connection_url, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true
})
//API Endpoints
app.get("/", (req, res) => res.status(200).send("Hello TheWebDev"))
...
MongoDB 模式和路由
MongoDB 以 JSON 格式存储数据,而不是像 Oracle 这样的传统数据库中的常规表结构。您创建了 MongoDB 所需的模式文件。它告诉你如何在 MongoDB 中存储字段。
这里,cards
被认为是一个集合名,您在数据库中存储一个类似于cardSchema
的值。它由一个有名字的对象和imgUrl
键组成。这些是您在 MongoDB 中使用的名称。创建一个dbCards.js
文件,将以下内容放入其中。
import mongoose from 'mongoose'
const cardSchema = mongoose.Schema({
name: String,
imgUrl: String
})
export default mongoose.model('cards', cardSchema)
现在,您可以使用该模式来创建向数据库添加数据的端点。这里遵循 MVC 模式;这是 web 应用的传统流程。点击 https://medium.com/createdd-notes/understanding-mvc-architecture-with-react-6cd38e91fefd
了解更多信息。
接下来,使用一个 POST 请求,从用户那里获取任何数据,并将其发送到数据库。您可以使用任何端点。例如,如果你写了一篇关于脸书的文章并点击了 POST 按钮,那么一旦发出 POST 请求,你的文章就会被保存在脸书数据库中。
GET 端点从数据库中获取所有数据。同样,你可以给出任何端点。例如,当您浏览脸书的提要时,一个 GET 请求被发送到端点,端点又从脸书数据库获取所有的帖子。
在server.js,
中,创建一个到/dating/cards
端点的 POST 请求。负载在req.body
到 MongoDB。然后你用create()
送dbCard
。如果成功,您会收到状态 201;否则,您会收到状态 500。更新的内容用粗体标记。
接下来,创建/dating/cards
的 GET 端点,从数据库中获取数据。您在这里使用find()
,如果成功,将收到状态 200(否则,状态 500)。更新的内容用粗体标记。
import express from 'express'
import mongoose from 'mongoose'
import Cards from './dbCards.js'
...
//API Endpoints
app.get("/", (req, res) => res.status(200).send("Hello TheWebDev"))
app.post('/dating/cards', (req, res) => {
const dbCard = req.body
Cards.create(dbCard, (err, data) => {
if(err) {
res.status(500).send(err)
} else {
res.status(201).send(data)
}
})
})
app.get('/dating/cards', (req, res) => {
Cards.find((err, data) => {
if(err) {
res.status(500).send(err)
} else {
res.status(200).send(data)
}
})
})
//Listener
app.listen(port, () => console.log(`Listening on localhost: ${port}`))
要查看路线,让我们使用邮递员应用。下载并安装它。
向http://localhost:8001
发送 GET 请求,检查它是否在 Postman 中工作,如图 2-11 所示。
图 2-11
初始路线检查
在处理 POST 请求之前,您需要完成两件事情。第一,实行 First 否则,当您稍后部署应用时,会出现跨来源错误。CORS(跨源资源共享)是限制从一个域访问另一个域的机制。假设你在http://example.com
上,想访问 http://mybank.com/accountdetails
。CORS 不会允许你这么做的。只有 http://mybank.com
允许与http://example.com
跨原点共享时才允许。
打开终端,在dating-app-backend
文件夹中安装 CORS。
npm i cors
在server.js
中,导入 CORS 并与app.use()
一起使用。你还需要使用express.json()
中间件。它是必需的,因为您需要它来解析来自 MongoDB 的传入 JSON 对象以读取主体。
更新后的代码用粗体标记。
import express from 'express'
import mongoose from 'mongoose'
import Cors from 'cors'
import Cards from './dbCards.js'
...
//Middleware
app.use(express.json())
app.use(Cors())
...
在 Postman 中,将请求更改为 POST,然后添加http://localhost:8001/dating/cards
端点。
接下来,点击身体,选择原始。从下拉菜单中选择 JSON(应用/json) 。在文本编辑器中,从DatingCards.js
文件中复制数据。通过在关键字中添加双引号来生成数据 JSON。
接下来,点击发送按钮。如果一切正确,您将获得状态:201 已创建(见图 2-12 )。
图 2-12
邮寄路线
您需要测试 GET 端点。将请求更改为 GET,然后单击发送按钮。如果一切正常,你得到状态:200 OK (见图 2-13 )。
图 2-13
获取路线
将后端与前端集成在一起
让我们把后端钩到前端。使用axios
包从前端调用。Axios 是一个 JavaScript 库,它向 REST 端点发出 API 请求。您刚刚在后端创建了两个端点。要访问它们,你需要 Axios。打开dating-app-frontend
文件夹并安装。
npm i axios
接下来,在components
文件夹中创建一个新的axios.js
文件,然后创建一个axios
的实例。基础 URL 是http://localhost:8001
。
import axios from 'axios'
const instance = axios.create({
baseURL: "http://localhost:8001"
})
export default instance
在DatingCards.js,
中,去掉处于people
状态的硬编码内容。然后导入本地的axios
并使用useEffect
钩子对/dating/cards
端点进行 API 调用。收到数据后,使用setPeople()
功能将其复位。更新后的代码用粗体标记。
import React, { useState, useEffect } from 'react'
import DatingCard from 'react-tinder-card'
import './DatingCards.css'
import axios from './axios'
const DatingCards = () => {
const [people, setPeople] = useState([])
useEffect(() => {
async function fetchData() {
const req = await axios.get("/dating/cards")
setPeople(req.data)
}
fetchData()
}, [])
const swiped = (direction, nameToDelete) => {
console.log("receiving " + nameToDelete)
}
...
去http://localhost:3000/
看数据。应用现已完成(见图 2-14 )。
图 2-14
应用完成
将后端部署到 Heroku
转到 www.heroku.com
部署后端。你按照第一章中的相同步骤创建了一个名为 dating-mern-backend 的应用。
返回axios.js
,将端点改为 https://dating-mern-backend.herokuapp.com
。如果一切正常,你的应用应该可以运行了。
import axios from 'axios'
const instance = axios.create({
baseURL: https://dating-mern-backend.herokuapp.com
})
export default instance
将前端部署到 Firebase
是时候在 Firebase 中部署前端了。遵循与第一章相同的程序。完成此过程后,站点应处于活动状态并正常工作,如图 2-15 所示。
图 2-15
部署的应用
摘要
在这一章中,我们在 MERN 堆栈中创建了一个约会应用。我们在 ReactJS 中构建前端,并在 Firebase 中托管它。后端构建在 NodeJS 中,托管在 Heroku 中。数据库是在 MongoDB 中构建的。
三、使用 MERN 打造短视频应用
欢迎来到您的下一个 MERN 项目,在这里您将使用 MERN (MongoDB,Express,React,Node.js)框架构建一个非常棒的短视频应用。后端在 Heroku 托管,前端站点使用 Firebase 托管。Material-UI ( https://material-ui.com
)提供项目中的图标。
这个 web 应用显示存储在 MongoDB 中的短视频,点击它就可以播放。您可以通过再次点按它来暂停它。这款网络应用还具有非常平滑的垂直滚动功能,可以显示更多视频。在图 3-1 中,可以看到 app 最终部署的版本。
图 3-1
部署版本
首先使用 React,然后移动到后端。打开您的终端并创建一个short-video-mern
文件夹。在里面,使用create-react-app
创建一个名为短视频前端的新应用。以下是命令。
mkdir short-video-mern
cd short-video-mern
npx create-react-app short-video-frontend
Firebase 托管初始设置
由于前端站点是通过 Firebase 托管的,所以可以在 create-react-app 创建 React app 的同时创建基本设置。按照第一章中的设置说明,我在 Firebase 控制台中创建了短视频 mern。
React 基本设置
回到 React 项目,将cd
转到short-video-frontend
目录。用npm start
启动 React 应用。
cd short-video-frontend
npm start
在index.js
、App.js
和App.css
中删除文件和基本设置就像在第二章中所做的一样。遵循这些指示。
图 3-2 显示了该应用在 localhost 上的外观。
图 3-2
初始应用
创建视频组件
接下来,在src
文件夹中创建一个components
文件夹。在components
文件夹中创建两个文件Video.js
和Video.css
。在Video.js
文件中,添加一个video
标签和一个垂直视频链接。我在我的频道上使用了我的 YouTube 短视频的链接。
以下是Video.js
内容。
import React from 'react'
import './Video.css'
const Video = () => {
return (
<div className="video">
<video
src="https://res.cloudinary.com/dxkxvfo2o/video/upload/v1608169738/video1_cvrjfm.mp4"
className="video__player"
loop
>
</video>
</div>
)
}
export default Video
在本地主机上的App.js
文件中包含Video
组件。更新后的代码用粗体标记。
import './App.css';
import Video from './components/Video';
function App() {
return (
<div className="app">
<div className="app__videos">
<Video />
<Video />
</div>
</div>
);
}
export default App;
接下来,将基本样式放在App.css
文件中,包括用于scroll-snap-type
的样式,它们是用于滚动的。你还需要让一切居中。接下来,为app__videos
类添加一些样式并隐藏滚动条。
html{
scroll-snap-type: y mandatory;
}
.app{
height: 100vh;
background-color: black;
display: grid;
place-items: center;
}
.app__videos{
position:relative;
height: 800px;
border-radius: 20px;
overflow: scroll;
width: 80%;
max-width: 500px;
scroll-snap-type: y mandatory;
}
.app__videos::-webkit-scrollbar{
display: none;
}
.app__videos{
-ms-overflow-style: none;
scrollbar-width: none;
}
图 3-3 显示了该应用在 localhost 上的外观。
图 3-3
显示的视频
您还需要设计Video.css
文件中的video
和video__player
类的样式。您在这里再次使用了scroll-snap-type
。
.video{
position: relative;
background-color: white;
width: 100%;
height:100%;
scroll-snap-align: start;
}
.video__player{
object-fit: fill;
width: 100%;
height: 100%;
}
捕捉特征完成。当你滚动时,它平稳地把你带到下一个视频,如图 3-4 所示。此外,通过 CSS,边缘在所有方面都变得完美。
图 3-4
捕捉特征
目前,视频无法播放。要让它们播放,必须使用一个引用(或 ref)。React 在虚拟 DOM 上工作。一般情况下,只需要在特殊情况下访问 DOM(文档对象模型),使用 refs 访问 DOM 元素。在这种情况下,您需要访问<video>
HTML 元素,以便能够访问play()
和pause()
属性,这些属性只能通过引用获得。
首先,导入useRef
和useState
钩子以获得videoRef
变量,该变量在 video 元素中使用,在这里创建一个onClick
处理程序来触发一个handleVideoPress
函数。
在handleVideoPress
函数内部,用playing
状态变量检查视频是否播放,然后用videoRef.current.pause()
设置暂停,将播放状态改为 false。你在else
区块做相反的动作。
更新后的Video.js
内容以粗体标记。
import React , { useRef, useState } from 'react'
import './Video.css'
const Video = () => {
const [playing, setPlaying] = useState(false)
const videoRef = useRef(null)
const handleVideoPress = () => {
if(playing){
videoRef.current.pause()
setPlaying(false)
} else {
videoRef.current.play()
setPlaying(true)
}
}
return (
<div className="video">
<video
src="https://res.cloudinary.com/dxkxvfo2o/video/upload/v1608169738/video1_cvrjfm.mp4"
className="video__player"
loop
ref={videoRef}
onClick={handleVideoPress}
>
</video>
</div>
)
}
export default Video
点击视频在本地主机上播放。再次点按它以暂停。
创建视频页脚组件
让我们处理第二个组件**,**,它显示了用户名、视频标题和视频页脚中的滚动滚动条。
在components
文件夹中创建两个文件VideoFooter.js
和VideoFooter.css
。然后将VideoFooter
组件包含在Video.js
文件中。更新后的代码用粗体标记。
import React , { useRef, useState } from 'react'
import './Video.css'
import VideoFooter from './VideoFooter'
const Video = () => {
...
return (
<div className="video">
<video
src="https://res.cloudinary.com/dxkxvfo2o/video/upload/v1608169738/video1_cvrjfm.mp4"
className="video__player"
loop
ref={videoRef}
onClick={handleVideoPress}
>
</video>
<VideoFooter />
</div>
)
}
export default Video
接下来,在VideoFooter.js
文件中添加一个包含用户名的h3
标签和一个包含描述的p
标签。
import React from 'react'
import './VideoFooter.css'
const VideoFooter = () => {
return (
<div className="videoFooter">
<div className="videoFooter__text">
<h3>@nabendu82</h3>
<p>Macbook Air to new Windows editing beast</p>
</div>
</div>
)
}
export default VideoFooter
接下来,在VideoFooter.css
文件中设置它们的样式。
.videoFooter{
position: relative;
color: white;
bottom: 150px;
margin-left: 40px;
display: flex;
}
.videoFooter__text{
flex: 1;
}
.videoFooter__text > h3{
padding-bottom: 20px;
}
.videoFooter__text > p{
padding-bottom: 20px;
}
图 3-5 显示了本地主机上的文本。
图 3-5
初始页脚
让我们首先安装 Material-UI,它提供了图标。根据 Material-UI 文档进行两次 npm 安装。通过short-video-frontend
文件夹中的集成端子安装铁芯。
npm i @material-ui/core @material-ui/icons
是时候在VideoFooter.js
文件中使用了。在videoFooter__ticker
div 中包含音符图标MusicNoteIcon
,它是从 Material-UI 导入的。
更新的内容用粗体标记。
import React from 'react'
import './VideoFooter.css'
import MusicNoteIcon from '@material-ui/icons/MusicNote'
const VideoFooter = () => {
return (
<div className="videoFooter">
<div className="videoFooter__text">
<h3>@nabendu82</h3>
<p>Macbook Air to new Windows editing beast</p>
<div className="videoFooter__ticker">
<MusicNoteIcon className="videoFooter__icon" />
</div>
</div>
</div>
)
}
export default VideoFooter
这个项目的特色是一个漂亮的跑马灯。为此,您在short-video-frontend
文件夹中安装一个名为react-ticker
的包。
npm i react-ticker
接下来,在VideoFooter.js
文件中包含文档中的股票代码和唱片(或旋转光盘)图像。正如你在新闻频道底部看到的,滚动条在屏幕上移动文本。还显示了一个录制/旋转的光盘图像,您可以很快在其中添加漂亮的动画。
更新的内容用粗体标记。
import React from 'react'
import './VideoFooter.css'
import MusicNoteIcon from '@material-ui/icons/MusicNote'
import Ticker from 'react-ticker'
const VideoFooter = () => {
return (
<div className="videoFooter">
<div className="videoFooter__text">
<h3>@nabendu82</h3>
<p>Macbook Air to new Windows editing beast</p>
<div className="videoFooter__ticker">
<MusicNoteIcon className="videoFooter__icon" />
<Ticker mode="smooth">
{({ index }) => (
<>
<p>I am a Windows PC</p>
</>
)}
</Ticker>
</div>
</div>
<img className="videoFooter__record" src="https://static.thenounproject.com/png/934821-200.png" alt="video footer" />
</div>
)
}
export default VideoFooter
接下来,在VideoFooter.css
文件中为滚动条和录制的图像添加样式。在这里,您将滚动条与音乐图标对齐,并添加动画来移动录制的图像。
将以下内容添加到VideoFooter.css
文件中。
.videoFooter__icon{
position: absolute;
}
.videoFooter__ticker > .ticker{
height: fit-content;
margin-left: 30px;
width: 60%;
}
.videoFooter__record{
animation: spinTheRecord infinite 5s linear;
height: 50px;
filter: invert(1);
position: absolute;
bottom: 0;
right: 20px;
}
@keyframes spinTheRecord {
from {
transform: rotate(0deg)
}
to {
transform: rotate(360deg)
}
}
图 3-6 显示了 localhost 上的页脚组件,包括一个滚动滚动条和旋转圆盘。
图 3-6
页脚完成
创建视频侧栏组件
现在让我们创建一个侧边栏组件,它在视频的右侧显示图标。
在components
文件夹中创建两个文件VideoSidebar.js
和VideoSidebar.css
。您还需要包含Video.js
文件。更新后的代码用粗体标记。
import React , { useRef, useState } from 'react'
import './Video.css'
import VideoFooter from './VideoFooter'
import VideoSidebar from './VideoSidebar'
const Video = () => {
...
return (
<div className="video">
<video
src="https://res.cloudinary.com/dxkxvfo2o/video/upload/v1608169738/video1_cvrjfm.mp4"
className="video__player"
loop
ref={videoRef}
onClick={handleVideoPress}
>
</video>
<VideoFooter />
<VideoSidebar />
</div>
)
}
export default Video
接下来,更新VideoSidebar.js
文件。这里,你使用了不同的材质界面图标。您还可以使用一个状态变量来保存 like 图标是否被按下;如果是这样,它会从空心图标变为实心图标,并且计数也会改变。
import React, { useState } from 'react'
import './VideoSidebar.css'
import FavoriteIcon from '@material-ui/icons/Favorite'
import FavoriteBorderIcon from '@material-ui/icons/FavoriteBorder'
import MessageIcon from '@material-ui/icons/Message'
import ShareIcon from '@material-ui/icons/Share'
const VideoSidebar = () => {
const [liked, setLiked] = useState(false)
return (
<div className="videoSidebar">
<div className="videoSidebar__button">
{ liked ? <FavoriteIcon fontSize="large" onClick={e => setLiked(false)} /> : <FavoriteBorderIcon fontSize="large" onClick={e => setLiked(true)} /> }
<p>{liked ? 101 : 100}</p>
</div>
<div className="videoSidebar__button">
<MessageIcon fontSize="large" />
<p>345</p>
</div>
<div className="videoSidebar__button">
<ShareIcon fontSize="large" />
<p>109</p>
</div>
</div>
)
}
export default VideoSidebar
接下来,更新VideoSidebar.css
文件。
.videoSidebar{
position: absolute;
top: 50%;
right: 10px;
color: white;
}
.videoSidebar__button{
padding: 20px;
text-align: center;
}
图 3-7 展示了这些可爱的图标,视频侧边栏就做好了。
图 3-7
侧栏已完成
使组件动态化
来自App.js
文件的所有数据被传递给子组件。您使组件成为动态的,以便可以向它们传递道具。像在 React 中一样,使用 props 将数据从父组件传递到子组件。视频侧边栏是第一个要处理的组件。在VideoSidebar.js
中,传递数字作为道具。
更新的内容用粗体标记。
...
const VideoSidebar = ({ likes, shares, messages }) => {
const [liked, setLiked] = useState(false)
return (
<div className="videoSidebar">
<div className="videoSidebar__button">
{ liked ? <FavoriteIcon fontSize="large" onClick={e => setLiked(false)} /> : <FavoriteBorderIcon fontSize="large" onClick={e => setLiked(true)} /> }
<p>{liked ? likes + 1 : likes }</p>
</div>
<div className="videoSidebar__button">
<MessageIcon fontSize="large" />
<p>{messages}</p>
</div>
<div className="videoSidebar__button">
<ShareIcon fontSize="large" />
<p>{shares}</p>
</div>
</div>
)
}
export default VideoSidebar
同样,在VideoFooter.js
文件中传递字符串作为道具。
更新的内容用粗体标记。
...
const VideoFooter = ({ channel, description, song }) => {
return (
<div className="videoFooter">
<div className="videoFooter__text">
<h3>@{channel} </h3>
<p>{description}</p>
<div className="videoFooter__ticker">
<MusicNoteIcon className="videoFooter__icon" />
<Ticker mode="smooth">
{({ index }) => (
<>
<p>{song}</p>
</>
)}
</Ticker>
</div>
</div>
<img className="videoFooter__record" src="https://static.thenounproject.com/png/934821-200.png" alt="video footer" />
</div>
)
}
export default VideoFooter
您希望进一步从应用组件钻取道具,以获得不同的视频文件。让我们将这些道具添加到Video.js
文件中并使用它们。
更新的内容用粗体标记。
...
const Video = ({ url, channel, description, song, likes, shares, messages }) => {
...
return (
<div className="video">
<video
src={url}
className="video__player"
loop
ref={videoRef}
onClick={handleVideoPress}
>
</video>
<VideoFooter channel={channel} description={description} song={song} />
<VideoSidebar likes={likes} shares={shares} messages={messages} />
</div>
)
}
export default Video
在App.js
中,你通过所有的道具,可以通过两个不同的视频。
更新的内容用粗体标记。
...
function App() {
return (
<div className="app">
<div className="app__videos">
<Video
url="https://res.cloudinary.com/dxkxvfo2o/video/upload/v1608169738/video1_cvrjfm.mp4"
channel="nabendu82"
description="Macbook Air to new Windows editing beast"
song="I am a Windows PC"
likes={345}
shares={200}
messages={90}
/>
<Video
url="https://res.cloudinary.com/dxkxvfo2o/video/upload/v1608169739/video2_mecbdo.mp4"
channel="thewebdev"
description="Tuesday morning editing on kdenlive in Windows"
song="Kdenlive is great"
likes={445}
shares={290}
messages={109}
/>
</div>
</div>
);
}
export default App;
前端完成了,该开始后端了。
初始后端设置
让我们转到后端,从 Node.js 代码开始。打开一个新的终端窗口,在根目录下创建一个新的short-video-backend
文件夹。移动到short-video-backend
目录后,输入git init
命令,这是 Heroku 稍后需要的。
mkdir short-video-backend
cd short-video-backend
git init
接下来,通过在终端中输入npm init
命令来创建package.json
文件。你被问了一堆问题;对于大多数情况,只需按下回车键。你可以提供描述和作者,但不是强制的。你一般在server.js
做进入点,这是标准的(见图 3-8 )。
图 3-8
初始服务器设置
一旦package.json
被创建,你需要创建包含node_modules
的.gitignore
文件,因为你不想以后将node_modules
推送到 Heroku。以下是.gitignore
文件的内容。
node_modules
接下来,打开package.json.
行"type"
:
"module"
需要在 Node.js 中启用类似 React 的导入,包括一个启动脚本来运行server.js
文件。
更新的内容用粗体标记。
{
"name": "short-video-backend",
"version": "1.0.0",
"description": " The short video app backend",
"main": "server.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "Nabendu Biswas",
"license": "ISC"
}
在开始之前,您需要安装两个软件包。打开终端,在short-video-backend
文件夹中安装 Express 和 Mongoose。正如第二章所讨论的,Express 是 Node.js 框架,通过它你可以轻松构建后端代码。Mongoose 是绑定 Node.js 和 MongoDB 所需的库,因此它是负责在 Node.js 代码中创建模式的桥梁。
npm i express mongoose
MongoDB 设置
MongoDB 的设置与第一章中描述的相同。按照这些说明,创建一个名为的新项目。
在继续之前,将nodemon
安装在short-video-backend
文件夹中。它帮助server.js
中的变化瞬间重启 Node 服务器。
npm i nodemon
初始路线设置
接下来,在short-video-backend
文件夹中创建一个server.js
文件。在这里,您导入 Express 和 Mongoose 包。然后使用 Express 创建一个运行在端口 9000 上的port
变量。
第一个 API 端点是一个由app.get()
创建的简单 GET 请求,如果成功,它会显示文本 Hello TheWebDev 。
然后,用app.listen()
监听端口。
import express from 'express'
import mongoose from 'mongoose'
//App Config
const app = express()
const port = process.env.PORT || 9000
//Middleware
//DB Config
//API Endpoints
app.get("/", (req, res) => res.status(200).send("Hello TheWebDev"))
//Listener
app.listen(port, () => console.log(`Listening on localhost: ${port}`))
在终端输入 nodemon server.js 查看监听 localhost: 9000 控制台日志。为了检查路线是否正常工作,转到http://localhost:9000/
查看端点文本,如图 3-9 所示。
图 3-9
本地主机
数据库用户和网络访问
在 MongoDB 中,您需要创建一个数据库用户并授予网络访问权限。该过程与第一章中的解释相同。遵循这些说明,然后获取用户凭证和连接 URL。
在server.js
中,创建一个connection_url
变量,并将 URL 粘贴到 MongoDB 的字符串中。您需要提供之前保存的密码和数据库名称。
更新后的代码用粗体标记。
...
//App Config
const app = express()
const port = process.env.PORT || 9000
const connection_url = ' mongodb+srv://admin:yourpassword@cluster0.ryj4g.mongodb.net/shortVideoDB?retryWrites=true&w=majority'
//Middleware
//DB Config
mongoose.connect(connection_url, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true
})
//API Endpoints
app.get("/", (req, res) => res.status(200).send("Hello TheWebDev"))
...
MongoDB 模式和路由
接下来,让我们创建 MongoDB 所需的模式文件。它告诉您字段在 MongoDB 中的存储方式。在short-video-backend
文件夹中创建一个dbModel.js
文件。
这里,shortVideos
被认为是一个集合名,您在数据库中存储一个类似于shortVideoSchema
的值。它由一个带有 URL、频道、描述、歌曲、喜欢、共享和消息键的对象组成。
import mongoose from 'mongoose'
const shortVideoSchema = mongoose.Schema({
url: String,
channel: String,
description: String,
song: String,
likes: String,
shares: String,
messages: String
})
export default mongoose.model('shortVideos', shortVideoSchema)
现在,您可以使用该模式来创建向数据库添加数据的端点。
在server.js
中,创建一个到/v2/posts
端点的 POST 请求。负载在req.body
到 MongoDB。然后使用create()
发送dbVideos.
如果成功,您将收到状态 201;否则,您会收到状态 500。
接下来,创建/v2/posts
的 GET 端点,从数据库中获取数据。你在这里用的是find()
。如果成功,您将收到状态 200(否则,状态 500)。
更新后的代码用粗体标记。
import express from 'express'
import mongoose from 'mongoose'
import Videos from './dbModel.js'
...
//API Endpoints
app.get("/", (req, res) => res.status(200).send("Hello TheWebDev"))
app.post('/v2/posts', (req, res) => {
const dbVideos = req.body
Videos.create(dbVideos, (err, data) => {
if(err)
res.status(500).send(err)
else
res.status(201).send(data)
})
})
app.get('/v2/posts', (req, res) => {
Videos.find((err, data) => {
if(err) {
res.status(500).send(err)
} else {
res.status(200).send(data)
}
})
})
//Listener
app.listen(port, () => console.log(`Listening on localhost: ${port}`))
为了检查路线,让我们使用真棒邮递员应用。向http://localhost:9000
发送 GET 请求,检查它是否在 Postman 中工作(见图 3-10 )。
图 3-10
获取请求
在处理 POST 请求之前,您需要完成两件事情。首先,实施 CORS。打开终端,在short-video-backend
文件夹中安装 CORS。
npm i cors
在server.js
中,导入 CORS,然后配合app.use()
使用。你还需要使用express.json()
中间件。
更新后的代码用粗体标记。
import express from 'express'
import mongoose from 'mongoose'
import Cors from 'cors'
import Videos from './dbModel.js'
...
//Middleware
app.use(express.json())
app.use(Cors())
...
在 Postman 中,将请求更改为 POST,然后添加http://localhost:9000/v2/posts
端点。
接下来,点击身体,选择原始。从下拉菜单中选择 JSON(应用/json) 。在文本编辑器中,从App.js
文件中复制数据。通过在关键字中添加双引号来生成数据 JSON。
然后,点击发送按钮。如果一切正确,你得到状态:201 已创建,如图 3-11 所示。
图 3-11
成功消息发布
我类似地插入了其他数据。您需要测试 GET 端点。将请求更改为 GET,然后单击发送按钮。如果一切正确,你得到状态:200 OK ,如图 3-12 所示。
图 3-12
成功消息获取
将后端与前端集成在一起
让我们用axios
包把后端钩到前端。打开short-video-frontend
文件夹并安装。
npm i axios
接下来,在components
文件夹中创建一个新的axios.js
文件,并创建一个axios
的实例。基础 URL 是http://localhost:9000
。
import axios from 'axios'
const instance = axios.create({
baseURL: "http://localhost:9000"
})
export default instance
在App.js
中,导入本地axios
。然后使用useEffect
钩子对/v2/posts
端点进行 API 调用。一旦收到数据,使用setVideos()
将其存储在videos
状态变量中。
在 return 语句中,去掉硬编码的东西。之后,映射视频数组,并将道具传递给视频组件。
更新的内容用粗体标记。
import React, { useState, useEffect } from 'react';
import './App.css';
import Video from './components/Video';
import axios from './components/axios';
function App() {
const [videos, setVideos] = useState([])
useEffect(() => {
async function fetchData() {
const res = await axios.get("/v2/posts")
setVideos(res.data)
return res
}
fetchData()
}, [])
return (
<div className="app">
<div className="app__videos">
{videos.map(({ url, channel, description, song, likes, shares, messages }) => (
<Video
key={url}
url={url}
channel={channel}
description={description}
song={song}
likes={likes}
shares={shares}
messages={messages}
/>
))}
</div>
</div>
);
}
export default App;
可以看到http://localhost:3000/
的数据。应用现在已经完成。但是在喜欢的数量上有一个小问题;它显示 3451 而不是 346(见图 3-13 )。
图 3-13。
出现此问题的原因是从数据库中传递字符串数字。在VideoSidebar.js
中,在喜欢的前面加一个 + ,把字符串改成数字。
...
<div className="videoSidebar__button">
{ liked ? <FavoriteIcon fontSize="large" onClick={e => setLiked(false)} /> : <FavoriteBorderIcon fontSize="large" onClick={e => setLiked(true)} /> }
<p>{liked ? +likes + 1 : likes}</p>
</div>
'''
将后端部署到 Heroku
转到 www.heroku.com
部署后端。按照你在第一章中所做的相同步骤,创建一个名为短视频后端的应用。
成功部署后,转到链接。图 3-14 显示了正确的文本。
图 3-14。
在axios.js
中,将端点改为 https://short-video-backend.herokuapp.com
。如果一切正常,你的应用应该可以运行了。
import axios from 'axios'
const instance = axios.create({
baseURL: " https://short-video-backend.herokuapp.com"
})
export default instance
将前端部署到 Firebase
是时候在 Firebase 中部署前端了。遵循与第一章相同的程序。完成此过程后,站点应处于活动状态并正常工作,如图 3-15 所示。
图 3-15。
摘要
在本章中,我们创建了一个短视频分享应用。我们在 ReactJS 中构建前端,并在 Firebase 中托管它。后端构建在 NodeJS 中,托管在 Heroku 中。数据库是在 MongoDB 中构建的。