TABLE、MODAl组件的CRUD,是我项目实战的入门功能。经过这一个功能,就能够基本了解到React在项目中如何使用。其实我踩过不少的坑,我尽可能把他们记录下来,让你们可以成功地跨过去。javascript
一.功能描述,基本的列表,可分页查询,弹窗方式的增删改。如图:java
二.功能代码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;
三. 坑点提示redis
1.return();方法里面的内容只容许有一个<div></div>,其余的组件可放入div里面。缓存
2.return();方法里面的组件,Table、Modal、Pagination组件使用以前,须要如今代码最前面import.可参考代码antd
3.使用Form需Cache = Form.create()(Cache); Cache是class的名称;FormItem的使用,需定义变量:const FormItem = Form.Item;app
4.在anted 2以上推荐使用getFieldDecorator。使用getFieldDecorator,经过方法this.props.form.getFieldsValue()能够获取到表单中各个字段的值。注意在render()方法里,在return()方法以前添加const {getFieldDecorator} = this.props.form; 具体使用可见代码less
5.具体使用ant desgin的组件好比Form的不少属性能够去官网上看说明。ide