预期效果
- 使用React、Express、Mongodb、node
- 可以前后端交互,实现增删查改
成品
![*pic 项目成果Gif图*](https://img-bed-1259149964.cos.ap-chengdu.myqcloud.com/Crud%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D.gif#pic_center)
实施过程
1. 创建项目
前端部分的创建
前端依然使用 react-create-app
来创建。
这次用到的依赖有如下的
"classnames": "^2.2.5",
"react-redux": "^5.0.7",
"react-router-dom": "^4.2.2",
"redux": "^3.7.2",
"redux-thunk": "^2.2.0"
偷懒直接从package.json粘的,嘿嘿
这里有一个陌生的,classnames是一个可以用表达式的形式来给DOM加class
的
其他的都是常用的。
目录结构
![*pic 项目目录*](https://img-bed-1259149964.cos.ap-chengdu.myqcloud.com/crud%E9%A1%B9%E7%9B%AE%E7%9B%AE%E5%BD%95.png#pic_center)
backend 是后台的文件夹,后台的代码就在server.js 中
public
下的index.html
是网页的起始。剩下的都是关于icon的
src 中
index.js 是项目的起始,页面的框架和路由在这里
registerServerWorker.js 在这个项目中并不需要
components 中是所有的页面组件
reducers ,,,就是reducer了~~~
actions 中,就是action ~~~
constants 中是变量,防止写错字符串类型但又报错报不到地方的问题
界面UI部分
这个小Demo只有三个tab,分别是home
页,其实啥都没有。中间是list
页,将提交的内容以卡片的形式展示出来。最后一个是form
页,提交数据用的。
这个小项目体验了前端配合node的后台,对数据库增删查改,所以我会以增删查改这四块来介绍这个小项目的逻辑。
Semantic UI
这个小项目的重心并不在样式,所以样式使用了Semantic UI
库,是用Boot CDN来引用的。
使用方法也非常简单,在public/index.html 中引用,就可以在所有页面都出现效果,但是编辑代码并不会有代码提示,像我这脑子不太好使的,基本只能看文档了,哈哈哈。下面是引用的代码
<link href="https://cdn.bootcss.com/semantic-ui/2.3.1/semantic.min.css" rel="stylesheet">
在其他页面使用的时候和 Bootstrap 非常相似,都是通过 className
来实现的,比如下面
<button className="ui primary button">Save</button>
tab部分
<div className="ui three item menu">
<NavLink exact activeClassName="active" className="item" to="/">Home</NavLink>
<NavLink exact activeClassName="active" className="item" to="/games">Games</NavLink>
<NavLink activeClassName="active" className="item" to="/games/new">Add New Game</NavLink>
</div>
这是样式,然后设置不同的路由,便可以进行tab切换了
<Route exact path="/" component={
Home } />
<Route exact path="/games" component={
GamesPage } />
···
自然,这些组件是要引入的,我这里就不写了。
exact
作用:让路径变得唯一,如果不加,会将两个组件的内容都渲染到后面的路由页面中。
例如:Home中有句“hello”,GamesPage中有句“world”,这样,在/games
中会出现 hello world。不过是两行显示。加入exact
后,每个路由只会渲染自己的组件。
后台搭建
在项目根目录创建一个后台的文件夹backend,里面的server.js 就是后台的入口文件。
这里使用的是node.js搭建,框架是express,数据库为Mongodb,语法为ES6, 所以肯定会用到Babel,另外使用nodemon,改变后台代码后会自动重启服务器。
Babel的用法大家还是看官网了,我用的版本比较老,是6.X,就不做介绍了,推荐使用较新的版本。
首先在server.js 中创建一个实例,并监听在某个端口,然后初始化后台,就能创建这个后台了。
import express from 'express';
const app = express();
app.listen(8180, () => console.log('Server is runing on localhost:8180'))
这个端口是可以任意设置的,但是尽量不要用一些常见的软件或者进程用的端口,不然可能经常由于端口占用而无法启动后台服务。
初始化,express、nodemon、babel安装
npm init -y
npm install express --save
npm install nodemon --save-dev
npm install --save-dev babel-cli babel-preset-env
然后在package.json 中修改start
的方法
"start": "nodemon --exec babel-node -- ./server.js"
最后,在终端运行就可以了,如果终端出现了我们 app.listen()
的回调函数的那句话就说明成功了
npm run start
数据库MongoDB的安装与启动
安装Mongodb,我用的是windows电脑(说实话相对 MAC 麻烦一些的),去官网下载可执行文件,下载后常规安装即可,最后有一个Install MongoDB Compass
可以不用勾选,这是一个可视化程序,勾选上安装太慢了,可以后面再安装或者根据自己喜好安装其他的。
以下方法都是基于Windows的方法,如果大家是Mac或者Linux可以去官方文档或者其他文档看一看,因为我没有验证过,所以也不敢随便写。
新建一个数据库存放的文件夹,其中存放数据。
mkdir E:mongodb\data
当然,在文件管理器中建立也是一样的。
命令行运行MongoDB服务器
C:\mongodb\bin\mongod --dbpath E:\mongodb\data
C:\mongodb\bin\mongod
是默认安装位置的mongodb启动程序
如果执行成功,就会输出一些日志信息。**这种方法虽然可以启动mongodb服务器,但是每次启动都要输入这段程序有些太麻烦了,下面介绍一下更加简洁的方法。**由于MongoDB v4.0之后,安装后会自动将mongodb服务添加到windows的服务中,并可以自启动。我们需要做的就会特别简单。
首先需要建立一个日志文件夹
mkdir E:mongodb\log
当然也可以在文件管理中建立。
然后将日志信息定位到这个文件夹中即可,方法是 打开安装目录下C:\mongodb\bin\mongod.cfg
- 将其中的
storage:
下dbpath
改为 E:\mongodb\data
。
- 将
systemLog:
下path
改为 E:\mongodb\log\mongod.log
。
- 有人说要修改port,我没修改,跑程序并没有报错,就略过了,以后出错了再看看,哈哈哈,贱
-
注意一下,这个文件最后有没有一句
mp:
有的话就删了,原因不懂,但是装在C盘好像就会出现这个,不删掉服务器跑不起来
最后贴一下修改后的配置文件
![*pic mongod.cfg修改后*](https://img-bed-1259149964.cos.ap-chengdu.myqcloud.com/mongod.cfg%E4%BF%AE%E6%94%B9%E5%90%8E%E6%88%AA%E5%9B%BE.png#pic_center)
这时候可以打开 Windows的服务,重新启动MongoDB Server
![*pic 重启MongoDB*](https://img-bed-1259149964.cos.ap-chengdu.myqcloud.com/%E9%87%8D%E5%90%AFMongoDB%20Server.png#pic_center)
Express 会在程序中后端创建后再初始化安装,就放到后面再说了。下面直接开始这个项目
后台连接Mongodb服务器
首先需要一个库,常见的有mongodb,mongoose等等,我其实都没用过。
这个项目使用的是mongodb,算是最底层的一个。
贴一段代码
import mongodb from 'mongodb';
const dbUrl = "mongodb://localhost";
mongodb.MongoClient.connect(dbUrl, (err, client) => {
if (err) throw err;
const db = client.db('crud')
app.get('/api/games', (req, res) => {
db.collection('games').find({
}).toArray((err, games) => {
res.json({
games });
});
});
app.listen(8180, () => console.log('Server is running on localhost:8180'));
})
首先引入mongodb这个库,dbUrl
是数据库的地址,这里就是本地了。
后面一句是连接方法,具体看看文档,由于某些原因,我一直打不开官方网站,就不给大家放网址了。放一个菜鸟教程的,可能由于版本更新,会有变化。
然后判断是否有错,有错就抛出来,然后指定数据库为 crud
。
之后是一个对api
的处理,作用是找到数据库中所有数据,转换成数组,加一个回调函数,输出json
格式。
后面监听的那句也放到连接数据库的方法里面,因为只有数据库连接了再监听才有意义。
最后注意一下 ,前端要跟后台交流,前端需要设置一个代理,代理到后台的地址和端口8180,方法是在最外层的 package.json 中加这样一句
"proxy": "http://localhost:8180"
后台的搭建,数据库连接基本就这些内容,下面就看一下前端是如何对后台数据库进行增删查改的。
查
redux
首先将redux建立起立,新建一个reducers文件夹,其中的index.js 使用了辅助函数 combineReducers
在 Redux 中,只有一个 store,但是 combineReducers
可以让你拥有多个 reducer,同时保持各自负责逻辑块的独立性
combineReducers
可以把多个不同 reducer 函数作为 value 的 object,合并成一个最终的 reducer 函数。但是这个小项目其实只有 games
一个reducer,是不是这样写都可以。
详细的关于 combineReducers
的了解可以看看这里
下面贴一下代码
import {
combineReducers } from 'redux';
import games from './games';
export default combineReducers({
games });
引入的games
就是一个普通的reducer
了
const games = (state = []) => {
return state;
}
export default games;
可以看到,这里state就是一个数组
使用reducer中数据
在components 中新建 GamesPage.js ,这里主要用来接收 store
中的数据,将其返回到页面,连接后台,会有查,和删的内容。
先贴一下代码
class GamesPage extends Component {
componentDidMount() {
this.props.fetchGames();
}
render() {
return (
<div>
<GamesList games={
this.props.games }/>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
games: state.games
};
}