Skip to content

Latest commit

 

History

History
1011 lines (730 loc) · 29.1 KB

File metadata and controls

1011 lines (730 loc) · 29.1 KB

三、使用 MERN 打造短视频应用

欢迎来到您的下一个 MERN 项目,在这里您将使用 MERN (MongoDB,Express,React,Node.js)框架构建一个非常棒的短视频应用。后端在 Heroku 托管,前端站点使用 Firebase 托管。Material-UI ( https://material-ui.com )提供项目中的图标。

这个 web 应用显示存储在 MongoDB 中的短视频,点击它就可以播放。您可以通过再次点按它来暂停它。这款网络应用还具有非常平滑的垂直滚动功能,可以显示更多视频。在图 3-1 中,可以看到 app 最终部署的版本。

img/512020_1_En_3_Chapter/512020_1_En_3_Fig1_HTML.jpg

图 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 的同时创建基本设置。按照第 1 章中的设置说明,我在 Firebase 控制台中创建了短视频 mern。

React 基本设置

回到 React 项目,将cd转到short-video-frontend目录。用npm start启动 React 应用。

cd short-video-frontend
npm start

index.jsApp.jsApp.css中删除文件和基本设置就像在第 2 章中所做的一样。遵循这些指示。

3-2 显示了该应用在 localhost 上的外观。

img/512020_1_En_3_Chapter/512020_1_En_3_Fig2_HTML.jpg

图 3-2

初始应用

创建视频组件

接下来,在src文件夹中创建一个components文件夹。在components文件夹中创建两个文件Video.jsVideo.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 上的外观。

img/512020_1_En_3_Chapter/512020_1_En_3_Fig3_HTML.jpg

图 3-3

显示的视频

您还需要设计Video.css文件中的videovideo__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,边缘在所有方面都变得完美。

img/512020_1_En_3_Chapter/512020_1_En_3_Fig4_HTML.jpg

图 3-4

捕捉特征

目前,视频无法播放。要让它们播放,必须使用一个引用(或 ref)。React 在虚拟 DOM 上工作。一般情况下,只需要在特殊情况下访问 DOM(文档对象模型),使用 refs 访问 DOM 元素。在这种情况下,您需要访问<video> HTML 元素,以便能够访问play()pause()属性,这些属性只能通过引用获得。

首先,导入useRefuseState钩子以获得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.jsVideoFooter.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 显示了本地主机上的文本。

img/512020_1_En_3_Chapter/512020_1_En_3_Fig5_HTML.jpg

图 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 上的页脚组件,包括一个滚动滚动条和旋转圆盘。

img/512020_1_En_3_Chapter/512020_1_En_3_Fig6_HTML.jpg

图 3-6

页脚完成

创建视频侧栏组件

现在让我们创建一个侧边栏组件,它在视频的右侧显示图标。

components文件夹中创建两个文件VideoSidebar.jsVideoSidebar.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 展示了这些可爱的图标,视频侧边栏就做好了。

img/512020_1_En_3_Chapter/512020_1_En_3_Fig7_HTML.jpg

图 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 )。

img/512020_1_En_3_Chapter/512020_1_En_3_Fig8_HTML.jpg

图 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。正如第 2 章所讨论的,Express 是 Node.js 框架,通过它你可以轻松构建后端代码。Mongoose 是绑定 Node.js 和 MongoDB 所需的库,因此它是负责在 Node.js 代码中创建模式的桥梁。

npm i express mongoose

MongoDB 设置

MongoDB 的设置与第 1 章中描述的相同。按照这些说明,创建一个名为的新项目。

在继续之前,将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 所示。

img/512020_1_En_3_Chapter/512020_1_En_3_Fig9_HTML.jpg

图 3-9

本地主机

数据库用户和网络访问

在 MongoDB 中,您需要创建一个数据库用户并授予网络访问权限。该过程与第 1 章中的解释相同。遵循这些说明,然后获取用户凭证和连接 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 )。

img/512020_1_En_3_Chapter/512020_1_En_3_Fig10_HTML.jpg

图 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 所示。

img/512020_1_En_3_Chapter/512020_1_En_3_Fig11_HTML.jpg

图 3-11

成功消息发布

我类似地插入了其他数据。您需要测试 GET 端点。将请求更改为 GET,然后单击发送按钮。如果一切正确,你得到状态:200 OK ,如图 3-12 所示。

img/512020_1_En_3_Chapter/512020_1_En_3_Fig12_HTML.jpg

图 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 )。

img/512020_1_En_3_Chapter/512020_1_En_3_Fig13_HTML.jpg

图 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 部署后端。按照你在第 1 章中所做的相同步骤,创建一个名为短视频后端的应用。

成功部署后,转到链接。图 3-14 显示了正确的文本。

img/512020_1_En_3_Chapter/512020_1_En_3_Fig14_HTML.jpg

图 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 中部署前端了。遵循与第 1 章相同的程序。完成此过程后,站点应处于活动状态并正常工作,如图 3-15 所示。

img/512020_1_En_3_Chapter/512020_1_En_3_Fig15_HTML.jpg

图 3-15。

摘要

在本章中,我们创建了一个短视频分享应用。我们在 ReactJS 中构建前端,并在 Firebase 中托管它。后端构建在 NodeJS 中,托管在 Heroku 中。数据库是在 MongoDB 中构建的。