项目实战之TABLE、MODAL组件的CRUD实现
TABLE、MODAl组件的CRUD,是我项目实战的入门功能。通过这一个功能,就可以基本了解到React在项目中如何使用。其实我踩过很多的坑,我尽量把他们记录下来,让大家能够成功地跨过去。
一.功能描述,基本的列表,可分页查询,弹窗方式的增删改。如图:

二.功能代码
import React from 'react';
import './index.less';
import {Button, Table, Icon, Affix, Modal, Form, Input, Checkbox, Pagination,Select} from 'antd';
import {message, notification} from 'antd';
import request from '../../utils/request.js';
import moment from 'moment';
const FormItem = Form.Item;
const logger = Logger.getLogger('Cache');
const clusterData = ['select an option','man', 'ware'];
class Cache extends React.Component {
constructor(props) {
super(props);
this.state = {
visible: false,
data: [],
tableLoading: false, // 表格是否是loading状态
currentPage: 1, // 当前第几页
pageSize: 20, // pageSize暂时不可修改, 固定20
total: 0, // 总共有多少条数据
checkStatus: 0
}
}
/**
* 刚进入页面时触发一次查询
*/
componentDidMount() {
this.refresh();
}
/**
* 切换分页时触发查询
*
* @param page
*/
handlePageChange = (page) => {
logger.debug('handlePageChange, page = %d', page);
this.setState({tableLoading: true});
const hide = message.loading('正在查询...', 0);
const url = `...`;//具体访问地址
const obj = {};
obj.page = page;
request.POST(url,obj)
.then(resp => {
hide();
const result = JSON.parse(resp);
if(result.code === 100){
this.setState({
currentPage: page, //当前页
data: result.data, //由后台返回的记录集
total: result.total, //记录的总条数
tableLoading: false,
});
}
})
.fail(error => {
hide();
...//可增加失败相关处理
})
}
/**
* 按当前的查询条件重新查询一次
*/
refresh = () => {
this.setState({tableLoading: true});
const hide = message.loading('正在查询...', 0);
const url = `...`;// 拼接要请求的url地址
const obj = {};
obj.page = this.state.currentPage;
request.POST(url,obj)
.then(resp => {
hide();
const result = JSON.parse(resp);
if(result.code === 100){
this.setState({
data: result.data,
total: result.total,
tableLoading: false,
});
}
})
.fail(error => {
hide();
...//可增加失败的相关处理
})
}
//点击doAdd操作
handleOk = (e) => {
const newObj = {};
const oldObj = this.props.form.getFieldsValue();
Object.assign(newObj, oldObj, {
isHash: this.state.checkStatus
})
this.setState({
visible: false,
});
if (this.state.modalInsert) {
this.handleInsert(newObj);
} else {
this.handleUpdate(newObj);
}
}
//选中是true值转为1,否则就是0
handleIsChecked = (e) => {
this.setState({
checkStatus: e.target.checked ? 1: 0
})
}
handleInsert = (obj) => {
const url = `...`; //添加方法的访问地址
const hide = message.loading('正在新增...', 0);
logger.debug('handleInsert: url = %s, obj = %o', url, obj);
request.POST(url, obj)
.then(resp => {
hide();
const result = JSON.parse(resp);
if(result.code === 100){
notification.success({
message: '新增成功',
description: '。。。',
duration: 3,
});
this.refresh();
}
})
.fail(error => {
hide();
...//失败相关处理
})
}
handleUpdate = (obj) => {
const key = obj.id;
const url = `...`;
const hide = message.loading('正在更新...', 0);
logger.debug('handleUpdate: url = %s, obj = %o', url, obj);
request.POST(url, obj)
.then(resp => {
hide();
const result = JSON.parse(resp);
if(result.code === 100){
notification.success({
message: '更新成功',
description: '...',
duration: 3,
});
this.refresh();
}
})
.fail(error => {
hide();
...//失败时的相关处理
})
}
handleDelete = (id) => {
const url = `...`;
const hide = message.loading('正在删除...', 0);
logger.debug('handleDelete: url = %s', url);
const obj = {};
obj.id = id;
request.POST(url, obj)
.then(resp => {
hide();
const result = JSON.parse(resp);
if(result.code === 100){
notification.success({
message: '删除成功',
description: '...',
duration: 3,
});
this.refresh();
}
})
.fail(error => {
hide();
...//失败时的相关处理
})
}
//点击取消按钮的操作
handleCancel = (e) => {
this.setState({
visible: false,
});
}
//新增按钮操作
onClickInsert = (e) => {
e.preventDefault();
this.props.form.resetFields();
this.setState({
visible: true,
modalTitle: '新增缓存key', // modal标题
modalInsert: true, // 当前modal是用来insert还是update
});
}
//修改按钮操作
onClickUpdate = (record, e) => {
e.preventDefault();
this.props.form.resetFields();
//数据回显
this.props.form.setFieldsValue(record);
this.setState({
visible: true,
modalTitle: '修改缓存key', // modal标题
modalInsert: false, //true是insert;false是update
});
}
//删除按钮操作
onClickDelete = (id, e) => {
e.preventDefault();
Modal.confirm({
title: '确认删除吗?',
content: `当前选中的id: ${id}`,
onOk: () => {
this.handleDelete(id);
},
});
}
render() {
let self = this;
const clusterOptions = clusterData.map(cluster => <Option key={cluster}>{cluster}</Option>);
const formItemLayout = {
labelCol: {
xs: {span: 24},
sm: {span: 6},
},
wrapperCol: {
xs: {span: 24},
sm: {span: 14},
},
};
const tailFormItemLayout = {
wrapperCol: {
xs: {
span: 24,
offset: 0,
},
sm: {
span: 14,
offset: 6,
},
},
};
const {getFieldDecorator} = this.props.form;
const columns = [{
title: 'ID',
dataIndex: 'id',
key: 'id',
}, {
title: 'key值',
dataIndex: 'cacheKey',
key: 'cacheKey',
}, {
title: 'key值含义描述',
dataIndex: 'keyDesc',
key: 'keyDesc',
}, {
title: '所属redis集群',
dataIndex: 'belongCluster',
key: 'belongCluster',
}, {
title: '是否hash存储',
dataIndex: 'isHash',
key: 'isHash',
render: (text, record) => (
record.isHash == 1 ? '是':'否'
),
}, {
title: '创建时间',
dataIndex: 'created',
key: 'created',
render: (text, record) => (
moment(text).format('YYYY-MM-DD')
),
}, {
title: '修改时间',
dataIndex: 'modified',
key: 'modified',
render: (text, record) => (
moment(text).format('YYYY-MM-DD')
),
}, {
title: '操作',
key: 'action',
render: (text, record) => (
<span>
<a href="javascript:return false;" onClick={self.onClickUpdate.bind(this, record)}>修改</a>
<span className="ant-divider"/>
<a href="javascript:return false;" onClick={self.onClickDelete.bind(this, record.id)}>删除</a>
</span>
),
}];
return (
<div>
<div>
<Affix offsetTop={8}>
<Button type="primary" onClick={this.onClickInsert}>
<Icon type="plus-circle-o"/> 新增
</Button>
</Affix>
<Modal title={this.state.modalTitle} visible={this.state.visible}
onOk={this.handleOk} onCancel={this.handleCancel}>
<Form layout="horizontal" >
<FormItem {...formItemLayout} label="缓存Key">
{getFieldDecorator('cacheKey', {
rules: [{ required: true, message: 'Please input cacheKey!' }],
})(
<Input type="text" />
)}
</FormItem>
<FormItem {...formItemLayout} label="key值描述">
{getFieldDecorator('keyDesc', {
rules: [{ required: true, message: 'Please input keyDesc!' }],
})(
<Input type="textarea" autosize={{minRows: 2, maxRows: 6}}/>
)}
</FormItem>
<FormItem {...formItemLayout} label="所属redis集群">
{getFieldDecorator('belongCluster', {
initialValue: clusterData[0],
rules: [{ required: true, message: 'Please select keyDesc!' }],
})(
<Select>
{clusterOptions}
</Select>
)}
</FormItem>
<FormItem {...tailFormItemLayout} style={{marginBottom: 8}}>
{getFieldDecorator('isHash', {
valuePropName: 'checked'
})(
<Checkbox onChange={self.handleIsChecked.bind(this)}>是否hash存储</Checkbox>
)}
</FormItem>
<FormItem>
{getFieldDecorator('id', {
})(
<input type="hidden"/>
)}
</FormItem>
</Form>
</Modal>
</div>
<Table columns={columns} dataSource={this.state.data} pagination={false}/>
<Pagination defaultCurrent={1} total={this.state.total} current={this.state.currentPage}
pageSize={this.state.pageSize} onChange={self.handlePageChange.bind(this)}/>
</div>
);
}
}
Cache = Form.create()(Cache);
export default Cache;
三. 坑点提示
1.return();方法里面的内容只允许有一个<div></div>,其他的组件可放入div里面。
2.return();方法里面的组件,Table、Modal、Pagination组件使用之前,需要现在代码最前面import.可参考代码
3.使用Form需Cache = Form.create()(Cache); Cache是class的名称;FormItem的使用,需定义变量:const FormItem = Form.Item;
4.在anted 2以上推荐使用getFieldDecorator。使用getFieldDecorator,通过方法this.props.form.getFieldsValue()可以获取到表单中各个字段的值。注意在render()方法里,在return()方法之前添加const {getFieldDecorator} = this.props.form; 具体使用可见代码
5.具体使用ant desgin的组件比如Form的很多属性可以去官网上看说明。

浙公网安备 33010602011771号