React + Redux项目中Material UI表格行编辑功能实现咨询
没问题,我来帮你梳理这个Material UI表格编辑功能的实现细节~
解答你的Material UI表格编辑功能问题
一、是否需要额外引入Material UI组件?
你目前已经在使用TableRow、TableRowColumn等表格组件,以及EditIcon、TrashIcon图标组件。如果想要更流畅统一的Material风格编辑体验,建议额外引入以下组件:
Dialog:用于弹出编辑表单,避免页面布局混乱TextField:替换原生input,和现有Material组件风格保持一致DialogActions、FlatButton:用于弹窗的确认/取消操作按钮
如果只是简单复用现有原生input表单做编辑,也可以不用额外引入,但用Material组件的体验会更协调。
二、具体实现逻辑
你的代码已经有了handleClickEdit的雏形,接下来只需要完善状态管理、数据填充和提交逻辑即可,步骤如下:
1. 新增编辑相关状态
在组件的state里添加控制弹窗显示、存储当前编辑行数据的状态:
constructor(props) { super(props); this.state = { getExpense: [], selected: [], // 新增编辑状态 isEditing: false, currentEditRow: null, // 统一管理表单数据,方便添加/编辑复用 formData: { item_description: '', purchase_date: '', item_price: '', item_link: '' } }; }
2. 适配表单数据的handleChange
把原来直接修改顶层state的逻辑,改成修改formData对象:
handleChange = (name) => { return (event) => { this.setState(prevState => ({ formData: { ...prevState.formData, [name]: event.target.value } })); }; };
3. 完善编辑点击事件:填充数据并打开弹窗
点击编辑图标时,把当前行的数据赋值给表单,并打开编辑弹窗:
handleClickEdit = (row) => { this.setState({ isEditing: true, currentEditRow: row, formData: { item_description: row.item_description, purchase_date: row.purchase_date, item_price: row.item_price, item_link: row.item_link } }); };
4. 添加编辑提交和取消方法
// 提交编辑内容 handleEditSubmit = () => { const { currentEditRow, formData } = this.state; // 带上行id,让后端知道要更新哪条数据 this.props.dispatch({ type: 'EDIT_EXPENSE', payload: { id: currentEditRow.id, ...formData } }); // 关闭弹窗并清空编辑状态 this.setState({ isEditing: false, currentEditRow: null }); }; // 取消编辑 handleEditCancel = () => { this.setState({ isEditing: false, currentEditRow: null }); };
5. 实现编辑弹窗并复用表单
用Dialog组件封装编辑表单,同时把原来的添加表单替换为Material UI的TextField(保持风格统一):
// 在render函数里定义编辑弹窗 const editDialog = ( <Dialog title="Edit Expense" open={this.state.isEditing} onRequestClose={this.handleEditCancel} > <form> <TextField label="Item description" value={this.state.formData.item_description} onChange={this.handleChange('item_description')} fullWidth margin="normal" /> <TextField label="Purchase Date" value={this.state.formData.purchase_date} onChange={this.handleChange('purchase_date')} fullWidth margin="normal" /> <TextField label="Item price" value={this.state.formData.item_price} onChange={this.handleChange('item_price')} fullWidth margin="normal" /> <TextField label="Item link" value={this.state.formData.item_link} onChange={this.handleChange('item_link')} fullWidth margin="normal" /> <DialogActions> <FlatButton label="Cancel" onClick={this.handleEditCancel} /> <FlatButton label="Save" primary onClick={this.handleEditSubmit} /> </DialogActions> </form> </Dialog> );
然后在内容区域添加这个弹窗,同时修改添加表单:
// 原来的添加表单替换为Material UI TextField <form id="expenseForm"> <h3> Add a new <br /> expense </h3> <TextField placeholder="Item description" onChange={this.handleChange('item_description')} fullWidth margin="normal" /> <TextField placeholder="Purchase Date" onChange={this.handleChange('purchase_date')} fullWidth margin="normal" /> <TextField placeholder="Item price" onChange={this.handleChange('item_price')} fullWidth margin="normal" /> <TextField placeholder="Item link" onChange={this.handleChange('item_link')} fullWidth margin="normal" /> <br /> <RaisedButton id="expSubmit" label="Submit Expense" primary={true} style={style} onClick={this.handleClick} /> <h1>Total:</h1> <br /> <h3>$748.93</h3> </form> {/* 添加编辑弹窗 */} {editDialog}
6. 几个关键注意点
- 修正图标组件的类名:React里用
className而非class,把<EditIcon class="grow:hover"改成<EditIcon className="grow:hover" - 更新添加功能的
handleClick:提交formData而非顶层state,提交后清空表单 - 确保后端
EDIT_EXPENSE接口能接收带id的payload,正确更新对应数据
三、完整修改后的核心代码
这里整理了修改后的组件核心代码,你可以直接替换到你的项目中:
import React, { Component } from 'react'; import { connect } from 'react-redux'; // 新增引入需要的Material UI组件 import { Dialog, TextField, DialogActions, FlatButton } from '@material-ui/core'; import { Table, TableHeader, TableBody, TableRow, TableRowColumn, RaisedButton } from '@material-ui/core'; import EditIcon from '@material-ui/icons/Edit'; import TrashIcon from '@material-ui/icons/Delete'; const style = { margin: 12 }; const mapStateToProps = (state) => ({ user: state.user, reduxState: state.getExpense }); class ExpenseTable extends Component { constructor(props) { super(props); this.state = { getExpense: [], selected: [], isEditing: false, currentEditRow: null, formData: { item_description: '', purchase_date: '', item_price: '', item_link: '' } }; } isSelected = (index) => { return this.state.selected.indexOf(index) !== -1; }; handleRowSelection = (selectedRows) => { this.setState({ selected: selectedRows }); }; componentDidMount() { const { id } = this.props.match.params; this.props.dispatch({ type: USER_ACTIONS.FETCH_USER }); this.props.dispatch({ type: 'GET_EXPENSE' }); } componentDidUpdate() { if (!this.props.user.isLoading && this.props.user.userName === null) { this.props.history.push('home'); } } logout = () => { this.props.dispatch(triggerLogout()); }; handleChange = (name) => { return (event) => { this.setState(prevState => ({ formData: { ...prevState.formData, [name]: event.target.value } })); }; }; handleClick = () => { console.log('add expense', this.state.formData); this.props.dispatch({ type: 'ADD_EXPENSE', payload: this.state.formData }); // 提交后清空表单 this.setState({ formData: { item_description: '', purchase_date: '', item_price: '', item_link: '' } }); }; handleClickRemove = (id) => { console.log('delete expense', id); this.props.dispatch({ type: 'DELETE_EXPENSE', payload: id }); }; handleClickEdit = (row) => { this.setState({ isEditing: true, currentEditRow: row, formData: { item_description: row.item_description, purchase_date: row.purchase_date, item_price: row.item_price, item_link: row.item_link } }); }; handleEditSubmit = () => { const { currentEditRow, formData } = this.state; this.props.dispatch({ type: 'EDIT_EXPENSE', payload: { id: currentEditRow.id, ...formData } }); this.setState({ isEditing: false, currentEditRow: null }); }; handleEditCancel = () => { this.setState({ isEditing: false, currentEditRow: null }); }; render() { console.log('HEY-oooo expense render', this.state); let content = null; const editDialog = ( <Dialog title="Edit Expense" open={this.state.isEditing} onRequestClose={this.handleEditCancel} > <form> <TextField label="Item description" value={this.state.formData.item_description} onChange={this.handleChange('item_description')} fullWidth margin="normal" /> <TextField label="Purchase Date" value={this.state.formData.purchase_date} onChange={this.handleChange('purchase_date')} fullWidth margin="normal" /> <TextField label="Item price" value={this.state.formData.item_price} onChange={this.handleChange('item_price')} fullWidth margin="normal" /> <TextField label="Item link" value={this.state.formData.item_link} onChange={this.handleChange('item_link')} fullWidth margin="normal" /> <DialogActions> <FlatButton label="Cancel" onClick={this.handleEditCancel} /> <FlatButton label="Save" primary onClick={this.handleEditSubmit} /> </DialogActions> </form> </Dialog> ); if (this.props.user.userName) { const tableRows = this.props.reduxState.map((row) => { const { id, item_description, purchase_date, item_price, item_link } = row; return ( <TableRow selectable={false} key={id}> <TableRowColumn>{item_description}</TableRowColumn> <TableRowColumn>{purchase_date}</TableRowColumn> <TableRowColumn>${item_price}</TableRowColumn> <TableRowColumn><a href={item_link}>{item_link}</a></TableRowColumn> <TableRowColumn> <EditIcon className="grow:hover" onClick={() => this.handleClickEdit(row)} /> </TableRowColumn> <TableRowColumn> <TrashIcon onClick={() => this.handleClickRemove(id)} /> </TableRowColumn> </TableRow> ); }); content = ( <div> <form id="expenseForm"> <h3> Add a new <br /> expense </h3> <TextField placeholder="Item description" onChange={this.handleChange('item_description')} fullWidth margin="normal" /> <TextField placeholder="Purchase Date" onChange={this.handleChange('purchase_date')} fullWidth margin="normal" /> <TextField placeholder="Item price" onChange={this.handleChange('item_price')} fullWidth margin="normal" /> <TextField placeholder="Item link" onChange={this.handleChange('item_link')} fullWidth margin="normal" /> <br /> <RaisedButton id="expSubmit" label="Submit Expense" primary={true} style={style} onClick={this.handleClick} /> <h1>Total:</h1> <br /> <h3>$748.93</h3> </form> <Table> <TableHeader> <TableRow> <TableHeaderColumn>Item description</TableHeaderColumn> <TableHeaderColumn>Purchase Date</TableHeaderColumn> <TableHeaderColumn>Item Price</TableHeaderColumn> <TableHeaderColumn>Item Link</TableHeaderColumn> <TableHeaderColumn>Edit entry</TableHeaderColumn> <TableHeaderColumn>Delete entry</TableHeaderColumn> </TableRow> </TableHeader> <TableBody> {tableRows} </TableBody> </Table> {editDialog} </div> ); } return ( <div> <Nav /> {content} </div> ); } } export default connect(mapStateToProps)(ExpenseTable);
内容的提问来源于stack exchange,提问作者Just_some_Noob
相关产品推荐
相关产品推荐

