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