Передняя часть: приложение create-реагировать и реагировать на аксиомы
Серверная часть: node koa, продолжение mysql
Как новичок в интерфейсе, после попытки поработать над интерфейсом реакции в течение определенного периода времени, я хочу попробовать написать веб-сервисы с узлом, притворяясь очень мощным. После просмотра туториала по узлу + экспресс-туториала + туториала по koa я начал готовиться к самостоятельному написанию небольшого демо.
Внешний рендеринг (реакция + antd + create-react-app)
адрес гитхаба:node-react-koa
добавить изменить
удалять
Простая страница списка пользователей с запросом вверху, добавлением пользовательских кнопок, удалением, редактированием пользовательских кнопок в списке и разбиением на страницы внизу.Дизайн пользовательской таблицы в базе данных
(1) Передняя конструкция
1. Используйте леса Create-React-App, официально разработанные Facebook для создания фронтальной структуры RACT.
(1) Глобально установить приложение create-реагировать
npm install -g create-react-app
(2) Создать проект
create-react-app node-react-koa
cd node-react-koa && mkdir server //node服务都放在该文件下
npm run eject //可省略,只为了看配置 config
npm start
Из этого каталога проекта, как показано ниже
(3) Создание интерфейсных страниц
1. Установите antd, высококачественный компонент React, который работает «из коробки».antd design
npm install antd --save
2. УстановкаaxiosHTTP-библиотека на основе обещаний, которая работает в браузерах и node.js.
npm install axios --save
Поскольку это небольшая демонстрация, я рисую страницу прямо в src/App.js.
src/App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import axios from 'axios';
import { Table, Pagination, Input, Row, Button, Modal, Form } from 'antd';
import 'antd/dist/antd.css'
const { Search } = Input;
const FormItem = Form.Item;
const { confirm } = Modal;
class App extends Component {
constructor(props) {
super(props);
}
columns = [{
dataIndex: "username", title: "用户",
}, {
dataIndex: "age", title: "年龄",
}, {
dataIndex: "address", title: "地址"
}, {
dataIndex: "action", title: "操作", width: 200, render: (text, row) => {
return <div>
<Button onClick={() => this.modal('edit', row)} >编辑</Button>
<Button style={{ marginLeft: 10 }} type="danger" onClick={() => this.remove(row)} >删除</Button>
</div>
}
}];
state = {
dataSource: [{ username: "slf", age: "18", address: "杭州", id: 1 }],
current: 1,
size: 10,
total: 1,
visible: false,
modalType: "add"
}
componentDidMount() {
this.sizeChange(this.state.current,this.state.size);
}
//分页
sizeChange = (current, size) => {
//todo
}
//提交
handleOk = () => {
//todo
}
//添加编辑用户
modal = (type, row) => {
this.setState({
visible: true,
modalType: type
}, () => {
this.props.form.resetFields();
if (type === 'add') return;
this.props.form.setFieldsValue({
username: row.username,
age: row.age,
address: row.address
})
})
}
remove = (row) => {
confirm({
title: '是否要删除该用户?',
okText: '是',
okType: '否',
cancelText: 'No',
onOk() {
//todo
},
onCancel() {
//todo
},
});
}
render() {
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 4 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 },
},
};
return (
<div className="App">
<Row>
<Search style={{ width: 300 }} />
<Button type="primary" style={{ marginLeft: 20 }} onClick={() => this.modal('add')} >添加用户</Button>
</Row>
<Row style={{ paddingTop: 20 }}>
<Table dataSource={this.state.dataSource} rowKey={row => row.id} bordered columns={this.columns} pagination={false} />
</Row>
<Row style={{ paddingTop: 20 }}>
<Pagination
showTotal={(total) => `共 ${total} 条`}
current={this.state.current} total={this.state.total} pageSize={this.state.size}
onChange={this.sizeChange} />
</Row>
<Modal
title={this.state.modalType === 'add' ? "添加用户" : "编辑用户"}
onOk={this.handleOk}
onCancel={() => this.setState({ visible: false })}
visible={this.state.visible}
>
<Form>
<FormItem label="用户" {...formItemLayout}>
{getFieldDecorator('username', {
rules: [{ required: true, message: 'Please input your username!' }],
})(
<Input placeholder="Username" />
)}
</FormItem>
<FormItem label="年龄" {...formItemLayout}>
{getFieldDecorator('age', {
rules: [{ required: true, message: 'Please input your age!' }],
})(
<Input placeholder="age" />
)}
</FormItem>
<FormItem label="地址" {...formItemLayout}>
{getFieldDecorator('address', {
rules: [{ required: true, message: 'Please input your address!' }],
})(
<Input placeholder="address" />
)}
</FormItem>
</Form>
</Modal>
</div >
);
}
}
export default Form.create()(App);
Задача в приведенном выше коде — это место для отладки с серверной службой (идеальная версия внешнего интерфейса вставляется позже).
(2) Внутреннее строительство
В бэкэнд-конструкции я использовалkoaа такжеsequelize
база данных mysql
koa — среда веб-разработки следующего поколения на платформе Node.js.
Sequelize — спящий режим на стороне JS, который завершает операции CRUD со стороны сервера в базу данных.
1. Установите зависимости
npm install koa koa-body koa-cors koa-router sequelize mysql2 --save
koa-bodyПотому что веб-приложения не могут обойтись без обработки форм (таких как пользовательские формы добавления и редактирования). По сути, формы представляют собой пары ключ-значение, которые отправляются на сервер методом POST. Модуль koa-body можно использовать для извлечения пар ключ-значение из тела запроса POST.
koa-corsРешение междоменных проблем
koa-routerсопоставление обработчика URL
2. Подготовка
Создайте следующее в каталоге сервера:
/server/app.jsзапустить режим запуска файлаnode server/app.js
/server/routersПуть API внешнего доступа
/server/modelУровень данных: соединение с базой данных index.js, пользовательская таблица user.js
3. Создайте новый коа-сервис
/server/app.js
const Koa = require('koa');
const cors = require('koa-cors');
const router = require('./routers/index')
// 创建一个Koa对象表示web app本身:
const app = new Koa();
app.use(cors());//解决跨域问题
// 对于任何请求,app将调用该异步函数处理请求:
app.use(async (ctx, next) => {
console.log(ctx.request.path + ':' + ctx.request.method);
await next();
});
app.use(router.routes());
app.listen(3005);
console.log('app started at port 3005...');
4. Подключиться к базе данных
/server/model/index.js
operatorAliases должны писать true, иначе последующее использование sql вызовет проблемы, например, использование нечеткого запроса $like вызовет проблему Invalid value
const Sequelize = require('sequelize');
const sequelize = new Sequelize('数据库名', '用户名', '密码', {
host: 'localhost',
dialect: 'mysql',
operatorsAliases: true,
pool: {
max: 5, min: 0, acquire: 30000, idle: 10000
},
define: {
timestamps: false,
},
})
sequelize
.authenticate()
.then(() => {
console.log('Connection has been established successfully.');
})
.catch(err => {
console.error('Unable to connect to the database:', err);
});
module.exports = sequelize;
5. Таблица пользователей
Оформление по таблице
/server/model/user.js
sequelizeНажмите, чтобы узнать, как использовать
/server/model/user.js
const Sequelize = require('sequelize')
const sequelize = require('./index')
const User = sequelize.define('userinfos', {
id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true, unique: true },
username: { type: Sequelize.STRING },
age:{type:Sequelize.INTEGER},
address: { type: Sequelize.STRING },
isdelete: { type: Sequelize.INTEGER, allowNull: true }//软删除 0为未删除,1为删除
});
module.exports = User;
Приходят следующие моменты, в центре внимания этой статьи, напишите сервер! ! ! ! !
Поскольку проект небольшой, я написал его в каталоге маршрутизаторов.
/routers/index.js
1. Ввести для использованияkoa-body, koa-router, таблица данных (модель/user.js)
const koaBody = require('koa-body');
const router = require('koa-router')();
const User = require('../model/user');
2. Первый интерфейс API: получить список всех пользователей
router.get('/users', async (ctx, next) => {
const user = await User.findAll({
where: { isdelete: 0 },
})
ctx.body = user;
});
бегать
node server/app.js
почтальон тест
успех!
Формальные добавления, удаления и исправления начинаются ниже.
1. Увеличение числа пользователей Сначала вернитесь к src/App.js и улучшите метод отправки добавления.
handleOk = () => {
this.props.form.validateFieldsAndScroll((err, value) => {
if (err) return;
let data = {
username: value.username, age: value.age, address: value.address
};
if (this.state.modalType === 'add') {
axios.post("http://127.0.0.1:3005/user", data)
.then(msg => {
this.sizeChange(this.state.current, this.state.size);
this.setState({visible: false});
message.success('success!')
})
} else {
axios.put("http://127.0.0.1:3005/user/" + this.state.editRow.id, data)
.then(data => {
this.sizeChange(this.state.current, this.state.size);
this.setState({visible: false});
message.success('success!')
})
}
})
}
2. Добавить API сервер/маршрутизаторы/index.js
router.post('/user', koaBody(), async (ctx) => {
const user = await User.build(ctx.request.body).save();
ctx.body = user;
})
3. Редактируйте пользователей таким же образом сервер/маршрутизаторы/index.js
router.put('/user/:id', koaBody(), async (ctx) => {
const body = ctx.request.body;
const user = await User.findById(ctx.params.id);
await user.update({...body})
ctx.body = user;
})
4. Удалить пользователя сервер/маршрутизатор/index.js
router.delete('/user/:id', async (ctx) => {
const user = await User.findById(ctx.params.id).then((user) => user);
user.isdelete = 1;
await user.save();
ctx.body = { success: true }
})
5. Пейджинговый запрос сервер/маршрутизатор/index.js
//{"limit":10,"offset":0,"search":"slf"}
router.post('/user-search', koaBody(), async (ctx) => {
const body = ctx.request.body;
const user = await User.findAndCount({
where: {
isdelete: 0, username: {
$like: `%${body.search}%`
}
},
limit: body.limit,
offset: body.offset
});
ctx.body = user;
});
наконец
module.exports = router;
Идеальный передок
import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';
import axios from 'axios';
import {Table, Pagination, Input, Row, Button, Modal, Form, message} from 'antd';
import 'antd/dist/antd.css'
const {Search} = Input;
const FormItem = Form.Item;
const {confirm} = Modal;
class App extends Component {
constructor(props) {
super(props);
}
columns = [{
dataIndex: "username", title: "用户",
}, {
dataIndex: "age", title: "年龄",
}, {
dataIndex: "address", title: "地址"
}, {
dataIndex: "action", title: "操作", width: 200, render: (text, row) => {
return <div>
<Button onClick={() => this.modal('edit', row)}>编辑</Button>
<Button style={{marginLeft: 10}} type="danger" onClick={() => this.remove(row)}>删除</Button>
</div>
}
}];
state = {
dataSource: [],
current: 1,
size: 10,
total: 0,
visible: false,
modalType: "add",
search: "",
editRow: {}
}
componentDidMount() {
this.sizeChange(this.state.current, this.state.size);
}
//分页
sizeChange = (current, size) => {
let data = {
search: this.state.search,
limit: size,
offset: (parseInt(current) - 1) * size
}
axios.post("http://localhost:3005/user-search", data).then(data => {
this.setState({
dataSource: data.data.rows,
total: data.data.count,
current, size
})
})
};
//提交
handleOk = () => {
this.props.form.validateFieldsAndScroll((err, value) => {
if (err) return;
let data = {
username: value.username, age: value.age, address: value.address
};
if (this.state.modalType === 'add') {
axios.post("http://127.0.0.1:3005/user", data)
.then(msg => {
this.sizeChange(this.state.current, this.state.size);
this.setState({visible: false});
message.success('success!')
})
} else {
axios.put("http://127.0.0.1:3005/user/" + this.state.editRow.id, data)
.then(data => {
this.sizeChange(this.state.current, this.state.size);
this.setState({visible: false});
message.success('success!')
})
}
})
}
//添加编辑用户
modal = (type, row) => {
this.setState({
visible: true,
modalType: type
}, () => {
this.props.form.resetFields();
if (type === 'add') return;
this.props.form.setFieldsValue({
username: row.username,
age: row.age,
address: row.address
})
this.setState({editRow: row})
})
}
remove = (row) => {
let _this = this;
confirm({
title: '是否要删除该用户?',
okText: '是',
okType: '否',
cancelText: 'No',
onOk() {
axios.delete("http://127.0.0.1:3005/user/"+row.id)
.then(data=>{
_this.sizeChange(_this.state.current, _this.state.size);
message.success('success!')
})
}
});
};
search = (name) => {
this.setState({
search: name
}, () => {
this.sizeChange(1, 10)
})
};
render() {
const {getFieldDecorator} = this.props.form;
const formItemLayout = {
labelCol: {
xs: {span: 24},
sm: {span: 4},
},
wrapperCol: {
xs: {span: 24},
sm: {span: 16},
},
};
return (
<div className="App">
<Row>
<Search style={{width: 300}} onChange={this.search}/>
<Button type="primary" style={{marginLeft: 20}} onClick={() => this.modal('add')}>添加用户</Button>
</Row>
<Row style={{paddingTop: 20}}>
<Table dataSource={this.state.dataSource} rowKey={row => row.id} bordered columns={this.columns}
pagination={false}/>
</Row>
<Row style={{paddingTop: 20}}>
<Pagination
showTotal={(total) => `共 ${total} 条`}
current={this.state.current} total={this.state.total} pageSize={this.state.size}
onChange={this.sizeChange}/>
</Row>
<Modal
title={this.state.modalType === 'add' ? "添加用户" : "编辑用户"}
onOk={this.handleOk}
onCancel={() => this.setState({visible: false})}
visible={this.state.visible}
>
<Form>
<FormItem label="用户" {...formItemLayout}>
{getFieldDecorator('username', {
rules: [{required: true, message: 'Please input your username!'}],
})(
<Input placeholder="username"/>
)}
</FormItem>
<FormItem label="年龄" {...formItemLayout}>
{getFieldDecorator('age', {
rules: [{required: true, message: 'Please input your age!'}],
})(
<Input placeholder="age"/>
)}
</FormItem>
<FormItem label="地址" {...formItemLayout}>
{getFieldDecorator('address', {
rules: [{required: true, message: 'Please input your address!'}],
})(
<Input placeholder="address"/>
)}
</FormItem>
</Form>
</Modal>
</div>
);
}
}
export default Form.create()(App);
Резюме: я действительно хорош (бесстыжий)