使用 MongoDB,React,Node 和 Express(MERN)构建一个全栈应用
原文: Let’s build a full stack MongoDB, React, Node and Express (MERN) app
作者:jelo rivera
译者:博轩
为保证文章可读性,本文采用意译,而非直译
当我想从前端开发人员进阶到全栈开发人员时,我很难找到一篇文章,包含了我所需要学习的全部概念。
例如对数据库的了解,熟悉一门后端语言,如何将前后端整合,这些对于我来说,还有些陌生。这就是促使我完成这篇文章的原因:解决这个问题,以帮助我自己和其他前端工程师。
本文末尾包含了整个项目的 git 仓库地址,但我还是建议您先逐步学习本文,再去查看项目源码。这将帮助您更好地理解整个教程。:grinning:
这是我们的应用程序完成之后的样子,前端允许我们做一些增删改查的操作。
我们会从头开始构建这个应用。设置数据库,创建后端,并以最小的代价接入前端。
接下来,让我们做好准备,一起完成这个项目!
创建 Client
让我们创建项目的主目录。这将包含我们的应用程序的前端和后端的代码。
mkdir fullstack_app && cd fullstack_app
那么,让我们从前端开始吧。我们将使用 create-react-app
开始构建我们的前端,这意味着我们不必关注 Webpack
和 Babel
的配置(因为 create-react-app
默认对此进行了配置)。如果您还没有全局安装 create-react-app
,请使用下面的命令进行安装。
sudo npm i -g create-react-app
之后,我们就可以使用 create-react-app
来创建我们的 React
应用程序。只需在命令行中输入下面命令即可。
create-react-app client && cd client // 官方推荐 npx create-react-app client cd client npm start
我们还需要使用 Axios
来帮助我们封装 get/post 请求。现在让我们来安装它:
npm i -S axios
等待安装完毕,我们继续组织前端代码,以便我们之后接入后端。
PC 端用户:
del src\App.css src\App.test.js src\index.css src\logo.svg\
MAC 端用户:
rm src/App.css src/App.test.js src/index.css src/logo.svg
然后,让我们在 client
文件夹中编辑我们的 App.js
文件,让它只是渲染一些简单的东西。在我们准备好后端时,我们将进一步编辑此文件。
// client/src/App.js import React, { Component } from "react"; class App extends Component { render() { returnI'M READY TO USE THE BACK END APIS! :-); } } export default App;
我们还需要编辑 index.js
并删除一行代码。我们需要删除 ‘./index.css’
;现在,我们可以启动我们的 react
应用了。
// client/src/index.js import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.render( , document.getElementById('root') );
现在,只需要在命令行中输入:
npm start
接下来,打开浏览器并输入 http://localhost :3000/ ,您现在可以看到我们的前端已经启动了。
创建 Backend
回到我们的主目录,然后从那里开始创建我们的后端目录。我们将初始化此目录,以便为我们准备好之后构建需要的 package.json
。您将在终端看到一些 package.json
配置的详细信息,只需要按 回车 键直到完成即可。
mkdir backend && cd backend npm init // 也可以使用 npm init -y 来加速初始化
创建一个新文件,作为后端的主要代码,并将其命名为 server.js
。然后,在其中写入以下内容。这部分后端代码非常简洁、基础,我直接创建它,以便初学者不必考虑代码的复杂性,从而更快的理解代码的意图。然后,一旦理解了这段代码的意图,后续的操作也会更加轻松。为了便于理解,我在每个方法旁边都添加了注释。
const mongoose = require('mongoose'); const express = require('express'); var cors = require('cors'); const bodyParser = require('body-parser'); const logger = require('morgan'); const Data = require('./data'); const API_PORT = 3001; const app = express(); app.use(cors()); const router = express.Router(); //这是我们的MongoDB数据库 const dbRoute = 'mongodb://:@ds249583.mlab.com:49583/fullstack_app'; //将我们的后端代码与数据库连接起来 mongoose.connect(dbRoute, { useNewUrlParser: true }); let db = mongoose.connection; db.once('open', () => console.log('connected to the database')); //检查与数据库的连接是否成功 db.on('error', console.error.bind(console, 'MongoDB connection error:')); //(可选)仅用于记录和 // bodyParser,将请求体解析为可读的json格式 app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.use(logger('dev')); //这是我们的get方法 //此方法获取数据库中的所有可用数据 router.get('/getData', (req, res) => { Data.find((err, data) => { if (err) return res.json({ success: false, error: err }); return res.json({ success: true, data: data }); }); }); //这是我们的更新方法 //此方法会覆盖数据库中的现有数据 router.post('/updateData', (req, res) => { const { id, update } = req.body; Data.findByIdAndUpdate(id, update, (err) => { if (err) return res.json({ success: false, error: err }); return res.json({ success: true }); }); }); //这是我们的删除方法 //此方法删除数据库中的现有数据 router.delete('/deleteData', (req, res) => { const { id } = req.body; Data.findByIdAndRemove(id, (err) => { if (err) return res.send(err); return res.json({ success: true }); }); }); //这是我们的创造方法 //此方法在我们的数据库中添加新数据 router.post('/putData', (req, res) => { let data = new Data(); const { id, message } = req.body; if ((!id && id !== 0) || !message) { return res.json({ success: false, error: 'INVALID INPUTS', }); } data.message = message; data.id = id; data.save((err) => { if (err) return res.json({ success: false, error: err }); return res.json({ success: true }); }); }); //为我们的http请求添加 /api app.use('/api', router); //将我们的后端发送到端口 app.listen(API_PORT, () => console.log(`LISTENING ON PORT ${API_PORT}`));
您可能已经注意到我们的后端代码中已经设置了数据库的链接。别担心,这是我们文章的下一步。设置它会像之前那几步同样简单。首先,访问: MongoDB atlas ,并创建一个账户。 MongoDB atlas 将为我们提供一个免费的 500MB
的 MongoDB
数据库。它是托管在云端的,这也是我们行业当前的趋势,使我们能使用云端数据库。
设置好账户后,让我们登录网站。按照网站的提示,逐步创建集群,以及数据库管理员。下面是具体的步骤:
1、构建您的第一个集群
2、创建第一个数据库用户
3、将您的 IP
地址列入白名单(通常是你的本机地址)
4、连接您的群集
我们需要获取数据库的连接字符串,因此对于第4步,我们只需要单击创建的集群的连接按钮,如下所示。
然后点击弹窗底部的 “choose a connection method”
,选择 “Connect your Application”
。然后,复制字符串。
将此字符串 uri
粘贴到 server.js
文件中。找到 dbRoute
变量,将连接替换,并将你之前设置好的用户名,密码替换。
现在,回到我们的后端源代码。我们现在将配置我们的数据库,创建一个名为 data.js
的文件。代码如下:
// /backend/data.js const mongoose = require("mongoose"); const Schema = mongoose.Schema; // this will be our data base's data structure const DataSchema = new Schema( { id: Number, message: String }, { timestamps: true } ); // export the new Schema so we could modify it using Node.js module.exports = mongoose.model("Data", DataSchema);
到了这里,我们几乎已经完成了!让我们使用如下命令为后端安装依赖:
npm i -S mongoose express body-parser morgan cors
启动后端:
node server.js
我们可以在我们的控制台中看到它已准备好并正在侦听端口 3001
。让我们回到前端完成 MongoDB
+ Node.JS
+ Express.JS
系统所需的UI。
回到 /client/src/App.js
做出如下修改:
// /client/App.js import React, { Component } from 'react'; import axios from 'axios'; class App extends Component { // 初始化组件的状态 state = { data: [], id: 0, message: null, intervalIsSet: false, idToDelete: null, idToUpdate: null, objectToUpdate: null, }; // 当组件加载时,它首先要从数据库中获取所有的数据,这里会设置一个轮询逻辑,及时将数据在 `UI` 中更新。 componentDidMount() { this.getDataFromDb(); if (!this.state.intervalIsSet) { let interval = setInterval(this.getDataFromDb, 1000); this.setState({ intervalIsSet: interval }); } } // 永远不要让一个进程持续存在 // 当我们结束使用时,一定要杀死这个进程 componentWillUnmount() { if (this.state.intervalIsSet) { clearInterval(this.state.intervalIsSet); this.setState({ intervalIsSet: null }); } } // 我们的第一个使用后端api的get方法 // 从我们的数据库中获取数据 getDataFromDb = () => { fetch('http://localhost:3001/api/getData') .then((data) => data.json()) .then((res) => this.setState({ data: res.data })); }; // 使用 put 方法,在数据库里面插入一条新的数据 putDataToDB = (message) => { let currentIds = this.state.data.map((data) => data.id); let idToBeAdded = 0; while (currentIds.includes(idToBeAdded)) { ++idToBeAdded; } axios.post('http://localhost:3001/api/putData', { id: idToBeAdded, message: message, }); }; // 我们的删除方法使用我们的后端api // 删除现有数据库信息 deleteFromDB = (idTodelete) => { parseInt(idTodelete); let objIdToDelete = null; this.state.data.forEach((dat) => { if (dat.id == idTodelete) { objIdToDelete = dat._id; } }); axios.delete('http://localhost:3001/api/deleteData', { data: { id: objIdToDelete, }, }); }; // 我们的更新方法使用我们的后端api // 覆盖现有的数据库信息 updateDB = (idToUpdate, updateToApply) => { let objIdToUpdate = null; parseInt(idToUpdate); this.state.data.forEach((dat) => { if (dat.id == idToUpdate) { objIdToUpdate = dat._id; } }); axios.post('http://localhost:3001/api/updateData', { id: objIdToUpdate, update: { message: updateToApply }, }); }; render() { const { data } = this.state; return (); } } export default App;{data.length (
- id: {dat.id}
))}
data: {dat.message}this.setState({ message: e.target.value })} placeholder="add something in the database" style={{ width: '200px' }} />this.setState({ idToDelete: e.target.value })} placeholder="put id of item to delete here" />this.setState({ idToUpdate: e.target.value })} placeholder="id of item to update here" /> this.setState({ updateToApply: e.target.value })} placeholder="put new value of the item here" />
最后,我们编辑 package.json
,并在那里添加一个代理指向后端部署的端口。
{ "name": "client", "version": "0.1.0", "private": true, "dependencies": { "axios": "^0.18.0", "react": "^16.5.0", "react-dom": "^16.5.0", "react-scripts": "1.1.5" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" }, "proxy": "http://localhost:3001" }
请记住,这是前端部分的 package.json
,我们需要在 client
目录中去编辑。
现在,还剩下最后一点,就是同时启动后端和前端项目。
为此,让我们回到项目的根目录输入下面命令:
npm init -y npm i -S concurrently
编辑主项目目录的 package.json
:
{ "name": "fullstack_app", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "concurrently \"cd backend && node server.js\" \"cd client && npm start\"" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "concurrently": "^4.0.1" } }
现在,在命令行输入 npm start
启动我们的应用,它会帮我们打开浏览器,看到这个 MERN
(全栈) 的应用。我们可以在此之上任意扩展我们想要的功能。
哦,还有一件事。确保在浏览器上启用 CORS
,这使我们通过自己的机器调用自己的 API
。这是一个很棒的 插件 。:grimacing:
最后,这里是 git repo 。