[Full-Stack]React加Express前后端分离构建简单页面
React作为FaceBook家的前端框架,熟悉了它的语法之后,会觉得它真的挺好用的,Components的写法让构建页面变得更加简单方便。但是前端终究是要和后端通信的,本篇将采用Express作为后端,数据库选用Mysql,打通前后端连接,构建一个简单的页面,学习一下React和Express的基础语法。
技术栈
前端:
- React 18
- BootStrap 5
- axios
- yup(本文暂未使用)
- webpack
中间件:
- cors
- jwt(本文暂未使用)
后端:
- Express
- Sequelize
- Bcrypt(本文暂未使用)
- Mysql
- mysql2
后端
初始化后端环境
后端采用的是Express+Mysql+cors+Sequelize,在后端项目目录内(以server为例)使用npm包管理器安装它们。
srever>_ npm init
srever>_ npm install express mysql2 cors sequelize sequelize-cli nodemon
在服务器目录新建index.js:
const express = require('express'); const app = express(); //服务器监听端口3001 app.listen(3001,()=>{ console.log("server is live in 3001"); })
"scripts": { "start": "nodemon index.js", "test": "echo \"Error: no test specified\" && exit 1" },
server>_ npm start
此时,控制台应该会正常打印server is live in 3001,代表后端服务已正常开启。
初始化Sequelize驱动
Sequelize是用来驱动Mysql的(mysql2才是用来驱动数据库的,Sequelize是ORM),内置了crud的基本函数,使操作数据库变得更加简单,不必再手写sql语句。
在终端使用 npx sequelize-cli init 初始化驱动环境,它会给你的项目新增几个目录,其中config和models是我们需要关注的。
server/config-config.json保存的是数据库连接信息,server目录为你的后端项目目录。修改连接信息:
{ "development": { "username": "root", "password": "12345678", "database": "FullStack-React-Express", "host": "localhost", "dialect": "mysql" }
在server/models中新建Post.js文件(文件名随意),以json格式映射数据表字段:
module.exports = (sequelize, DataTypes) => { //使用sequelize驱动数据库如果Post表不存在则创建Posts表 const Posts = sequelize.define("Posts", { title: { type: DataTypes.STRING, allowNull: false, }, postText: { type: DataTypes.STRING, allowNull: false, }, username: { type: DataTypes.STRING, allowNull: false, }, }); return Posts; };
修改server/index.js:
const express = require('express'); const app = express(); // 导入数据库支持驱动sequelize const db = require('./models'); db.sequelize.sync().then(()=>{ //服务器监听端口3001 app.listen(3001,()=>{ console.log("server is live in 3001"); }) })
此时在终端ctrl+C关闭服务器,并npm start重新开启服务器,控制台会显示关于sequelize的信息,在后台运行了sql命令帮我们成功创建了Post表。
且表内包含:
title,postText,username,createdAt,updateAt。
前面三个是我们在server/models/Post.js中写的字段,后面两个则是sequelize自动创建的。
添加路由
路由可以简单理解为一个网络入口,如:http://localhost/posts
在服务器新建路由目录且新建路由文件server/routes/Posts.js:
const express = require('express'); const router = express.Router(); // 路由实现 router.get('/',(req,res)=>{ res.send("Hello World!") }); router.post('/'); module.exports = router;
并修改server/index.js文件:
const app = express(); // 导入数据库支持驱动sequelize const db = require('./models') //Post路由 const postRouter = require('./routes/Posts') //Post路由入口 http://localhost/posts app.use("/posts",postRouter) db.sequelize.sync().then(()=>{ //服务器监听端口3001 app.listen(3001,()=>{ console.log("server is live in 3001") }) })
此时,通过访问http://localhost/posts应该能看到显示Hello World!
在此推荐一个网络调试软件Insomnia。
使用create函数向数据库插入数据
前面提到Sequelize内置了一些操作sql的函数,create就是其中一个,用于创建数据(即sql的insert)。
修改server/index.js添加json解析:
const express = require('express'); const app = express(); //解析json数据 app.use(express.json());
修改 server/routes/Posts.js:
const express = require("express"); const router = express.Router(); const { Posts } = require("../models"); // get路由实现 router.get("/", (req, res) => { res.json("Hello World!"); }); // post路由实现 router.post("/", async (req, res) => { const post = req.body; //sequelize的语法插入数据 await Posts.create(post); res.json(post); }); module.exports = router;
主要是新增了router.post函数以及将Posts表从models中导入。
由于前端页面暂时还没创建好,我们使用Insomnia从后端模拟Post请求创建数据。
下载好Insomnia后,创建Post请求,地址为http://localhost:3001/posts,使用json格式数据向服务器发送请求信息。点我下载Insomnia
![](https://afish.org/wp-content/themes/CorePress/static/img/loading.gif)
可以看到,状态码为200,json数据已经成功发送到服务器,在数据库的Post表中已经有了新数据。
使用findAll函数从数据库查找数据
同理,从数据库查找数据我们需要使用get方法,修改server/routes/Posts.js中的get函数:
router.get("/", async (req, res) => { const listAllPost = await Posts.findAll(); res.json(listAllPost); });
依然使用Insomnia工具查看数据回显,创建get请求,地址为http://localhost:3001/posts,发起get请求,可以看到,已经成功从数据库中获取到之前创建的数据:
![](https://afish.org/wp-content/themes/CorePress/static/img/loading.gif)
客户端
在客户端目录(以client为例)使用react-create-app脚手架初始化React项目:
client>_ npm install react-create-app
client>_ npx react-create-app .
删除以下文件:
App.test.js,index.css,logo.svg
reportWEbVitals.js,setupTest.js(非必需步骤)
将client/src/App.js内容修改为:
import "./App.css"; function App() { return <div className="App">Hello React!</div>; } export default App;
client/src/index.js内容修改为:
import React from "react"; import {createRoot} from "react-dom/client"; import App from "./App"; // for React 17 : ReactDOM.render(<App />, document.getElementById('root')); createRoot(document.getElementById("root")).render(<App />);
client/src/App.css内仅保留第一个样式:
.App{ text-align: center; }
现在在客户端npm start,应该可以看到Hello React!字样。
在客户端安装axios实现跨域连接express
client>_ npm install axios
修改client/src/App.js,添加axios支持:
import "./App.css"; import axios from "axios"; import { useEffect } from "react"; function App() { useEffect(()=>{ axios.get("") },[]) return <div className="App"></div>; } export default App;
在服务器添加cors中间件连接axios(在本文最开始已经安装了cors,安装步骤可省略)
server>_ npm install cors
修改server/index.js添加cors支持:
const express = require('express'); const app = express(); const cors = require('cors'); //解析json数据 app.use(express.json()); //add cors support app.use(cors());
修改client/src/App.js:
function App() { useEffect(()=>{ axios.get("http://localhost:3001/posts").then((response) =>{ console.log(response); }) },[]) return <div className="App"></div>; } export default App;
添加useEffect和useState钩子函数前端显示数据库内容
修改client/src/App.js文件:
import "./App.css"; import axios from "axios"; //引入useEffect和useState钩子函数管理状态和副作用 import { useEffect, useState } from "react"; function App() { const [listAllPost, setlistAllPost] = useState([]); useEffect(() => { axios.get("http://localhost:3001/posts").then((response) => { setlistAllPost(response.data); }); }, []); //使用map映射取值 return ( <div className="App"> {listAllPost.map((value, key) => { return ( <div className="container"> <div class="title">{value.title}</div> <div class="text">{value.postText}</div> <div class="username">{value.username}</div> </div> ); })} </div> ); } export default App;
现在虽然前端能够显示数据库的内容,但是布局不够美观。
添加BootStrap美化页面布局
client>_ npm install bootstrp
修改client/src/index.js导入bootstrap库:
import 'bootstrap/dist/css/bootstrap.min.css';
修改client/src/App.js使用卡片布局:
import "./App.css"; import axios from "axios"; //引入useEffect和useState钩子函数管理状态和副作用 import { useEffect, useState } from "react"; function App() { const [listAllPost, setlistAllPost] = useState([]); useEffect(() => { axios.get("http://localhost:3001/posts").then((response) => { setlistAllPost(response.data); }); }, []); //使用map映射取值 return ( <div className="App"> {listAllPost.map((value, key) => { return ( <div className="container"> <div class="card mx-auto" style={{width:'500px'}}> <div class="card-body"> <h5 class="card-title">{value.title}</h5> <p class="card-text">{value.postText}</p> <h6 class="username">{value.username}</h6> </div> </div> </div> ); })} </div> ); } export default App;
至此,你可以得到一个页面布局相对美观的前端页面,并且从后端数据库成功拿到了内容显示在页面上。
![](https://afish.org/wp-content/themes/CorePress/static/img/loading.gif)
版权声明:
作者:小鱼
链接:https://afish.org/index.php/2023/10/27/full-stack_react_express/
来源:小鱼的blog
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论