You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:56:05