小知识点 React.createContext()
父组件可以直接传值到子组件、或者孙子组件,无需通过props进行传值,以前方便、简洁。包含Provider、Consumer组件,Provider的value属性就是所有子孙组件通用的都可以获取到的,而想使用这个value子孙组件必须被Consumer组件包裹
可编辑单元格的实现总体分为三部分
注意:如果需要使用状态组件,那么下面的代码会很适合你来使用,如果你要使用非状态组件,建议直接去antd( antd4+ )官网( https://ant-design.gitee.io/components/table-cn/#components-table-demo-edit-cell )看( 官网采用react的hooks,如果不了解的话可以去 https://react.html.cn/docs/hooks-overview.html 了解)
一、EditableRow ( 名字随意 )
class EditableRow extends Component {
returnForm = React.createRef();
render() {
return (
<Form ref={this.returnForm} component={false}>
//父组件
<EditableContext.Provider value={this.returnForm}>
<tr {...this.props} />
</EditableContext.Provider>
</Form>
);
}
}
二、EditableCell ( 名字随意 )
class EditableCell extends Component {
state = {
editing: false
};
toggleEdit = () => {
const editing = !this.state.editing;
this.setState({ editing }, () => {
if (editing) {
this.input.focus();
}
});
};
save = (e) => {
const { record, handleSave } = this.props;
let values = this.form.current.getFieldsValue();
this.toggleEdit();
handleSave({ ...record, ...values });
};
renderCell = (form) => {
this.form = form;
const { children, dataIndex, record, title } = this.props;
const { editing } = this.state;
let formParams = {
one: {
name: dataIndex,
rules: [
{
required: true,
message: `${title} is required.`
}
],
initialValue: record[dataIndex]
}
};
return editing ? (
<Form.Item {...formParams.one} style={{ margin: 0 }}>
<Input
ref={(node) => (this.input = node)}
onPressEnter={this.save}
onBlur={this.save}
/>
</Form.Item>
) : (
<div
className="editable-cell-value-wrap"
style={{ paddingRight: 24 }}
onClick={this.toggleEdit}
>
{children}
</div>
);
};
render() {
const {
editable,
dataIndex,
title,
record,
index,
handleSave,
children,
...restProps
} = this.props;
return (
<td {...restProps}>
{editable ? (
<EditableContext.Consumer>{this.renderCell}</EditableContext.Consumer>//子孙组件
) : (
children
)}
</td>
);
}
}
**三、EditableTable ( 名字随意 ) **
class EditableTable extends Component {
constructor(props) {
super(props);
this.columns = [
{
title: "name",
dataIndex: "name",
width: "30%",
editable: true
},
{
title: "age",
dataIndex: "age"
},
{
title: "address",
dataIndex: "address"
},
{
title: "operation",
dataIndex: "operation",
render: (_, record) =>
this.state.dataSource.length >= 1 ? (
<Popconfirm
title="Sure to delete?"
onConfirm={() => this.handleDelete(record.key)}
>
<a>Delete</a>
</Popconfirm>
) : null
}
];
this.state = {
dataSource: [
{
key: "0",
name: "Edward King 0",
age: "32",
address: "London, Park Lane no. 0"
},
{
key: "1",
name: "Edward King 1",
age: "32",
address: "London, Park Lane no. 1"
}
],
count: 2
};
}
handleDelete = (key) => {
const dataSource = [...this.state.dataSource];
this.setState({
dataSource: dataSource.filter((item) => item.key !== key)
});
};
handleAdd = () => {
const { count, dataSource } = this.state;
const newData = {
key: count,
name: `Edward King ${count}`,
age: "32",
address: `London, Park Lane no. ${count}`
};
this.setState({
dataSource: [...dataSource, newData],
count: count + 1
});
};
handleSave = (row) => {
const newData = [...this.state.dataSource];
const index = newData.findIndex((item) => row.key === item.key);
const item = newData[index];
newData.splice(index, 1, { ...item, ...row });
this.setState({
dataSource: newData
});
};
render() {
const { dataSource } = this.state;
const components = {
body: {
row: EditableRow,
cell: EditableCell
}
};
const columns = this.columns.map((col) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record) => ({
record,
editable: col.editable,
dataIndex: col.dataIndex,
title: col.title,
handleSave: this.handleSave
})
};
});
return (
<div>
<Button
onClick={this.handleAdd}
type="primary"
style={{
marginBottom: 16
}}
>
Add a row
</Button>
<Table
components={components}
rowClassName={() => "editable-row"}
bordered
dataSource={dataSource}
columns={columns}
/>
</div>
);
}
}
整体代码
//发送请求重新获取更改后的数据
import React,{Component} from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Table, Input, Button, Popconfirm, Form } from "antd";
const EditableContext = React.createContext(null);
class EditableRow extends Component {
returnForm = React.createRef();
render() {
return (
<Form ref={this.returnForm} component={false}>
<EditableContext.Provider value={this.returnForm}>
<tr {...this.props} />
</EditableContext.Provider>
</Form>
);
}
}
class EditableCell extends Component {
state = {
editing: false
};
toggleEdit = () => {
const editing = !this.state.editing;
this.setState({ editing }, () => {
if (editing) {
this.input.focus();
}
});
};
save = (e) => {
const { record, handleSave } = this.props;
let values = this.form.current.getFieldsValue();
this.toggleEdit();
handleSave({ ...record, ...values });
};
renderCell = (form) => {
this.form = form;
const { children, dataIndex, record, title } = this.props;
const { editing } = this.state;
let formParams = {
one: {
name: dataIndex,
rules: [
{
required: true,
message: `${title} is required.`
}
],
initialValue: record[dataIndex]
}
};
return editing ? (
<Form.Item {...formParams.one} style={{ margin: 0 }}>
<Input
ref={(node) => (this.input = node)}
onPressEnter={this.save}
onBlur={this.save}
/>
</Form.Item>
) : (
<div
className="editable-cell-value-wrap"
style={{ paddingRight: 24 }}
onClick={this.toggleEdit}
>
{children}
</div>
);
};
render() {
const {
editable,
dataIndex,
title,
record,
index,
handleSave,
children,
...restProps
} = this.props;
return (
<td {...restProps}>
{editable ? (
<EditableContext.Consumer>{this.renderCell}</EditableContext.Consumer>
) : (
children
)}
</td>
);
}
}
class EditableTable extends Component {
constructor(props) {
super(props);
this.columns = [
{
title: "name",
dataIndex: "name",
width: "30%",
editable: true
},
{
title: "age",
dataIndex: "age"
},
{
title: "address",
dataIndex: "address"
},
{
title: "operation",
dataIndex: "operation",
render: (_, record) =>
this.state.dataSource.length >= 1 ? (
<Popconfirm
title="Sure to delete?"
onConfirm={() => this.handleDelete(record.key)}
>
<a>Delete</a>
</Popconfirm>
) : null
}
];
this.state = {
dataSource: [
{
key: "0",
name: "Edward King 0",
age: "32",
address: "London, Park Lane no. 0"
},
{
key: "1",
name: "Edward King 1",
age: "32",
address: "London, Park Lane no. 1"
}
],
count: 2
};
}
handleDelete = (key) => {
const dataSource = [...this.state.dataSource];
this.setState({
dataSource: dataSource.filter((item) => item.key !== key)
});
};
handleAdd = () => {
const { count, dataSource } = this.state;
const newData = {
key: count,
name: `Edward King ${count}`,
age: "32",
address: `London, Park Lane no. ${count}`
};
this.setState({
dataSource: [...dataSource, newData],
count: count + 1
});
};
handleSave = (row) => {
const newData = [...this.state.dataSource];
const index = newData.findIndex((item) => row.key === item.key);
const item = newData[index];
newData.splice(index, 1, { ...item, ...row });
this.setState({
dataSource: newData
});
};
render() {
const { dataSource } = this.state;
const components = {
body: {
row: EditableRow,
cell: EditableCell
}
};
const columns = this.columns.map((col) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record) => ({
record,
editable: col.editable,
dataIndex: col.dataIndex,
title: col.title,
handleSave: this.handleSave
})
};
});
return (
<div>
<Button
onClick={this.handleAdd}
type="primary"
style={{
marginBottom: 16
}}
>
Add a row
</Button>
<Table
components={components}
rowClassName={() => "editable-row"}
bordered
dataSource={dataSource}
columns={columns}
/>
</div>
);
}
}
ReactDOM.render(<EditableTable />, document.getElementById("container"));