Skip to content

Instantly share code, notes, and snippets.

@iamso1
Last active September 25, 2020 09:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iamso1/0dc057813374053575a6752f62b1bf58 to your computer and use it in GitHub Desktop.
Save iamso1/0dc057813374053575a6752f62b1bf58 to your computer and use it in GitHub Desktop.
antdesign edit table with hook
import React, { useContext, useState, useEffect, useRef } from 'react';
import { Table, Input, Button, Popconfirm, Form } from 'antd';
const myData = {
myData: [
{
key: '1',
name: 'John Brown',
a: '1',
b: '2',
c: '3',
d: '4',
e: '5',
age: 32,
address: 'New York No. 1 Lake Park',
},
{
key: '2',
name: 'Jim Green',
a: '1',
b: '2',
c: '3',
d: '4',
e: '5',
age: 42,
address: 'London No. 1 Lake Park',
},
{
key: '3',
name: 'Joe Black',
a: '1',
b: '2',
c: '3',
d: '4',
e: '5',
age: 32,
address: 'Sidney No. 1 Lake Park',
},
{
key: '4',
name: 'Jim Red',
a: '1',
b: '2',
c: '3',
d: '4',
e: '5',
age: 32,
address: 'London No. 2 Lake Park',
},
],
};
const { Column, ColumnGroup } = Table;
const EditableContext = React.createContext();
const EditableRow = ({ index, ...props }) => {
const [form] = Form.useForm();
return (
<Form form={form} component={false}>
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
</Form>
);
};
const EditableCell = ({
title,
editable,
children,
dataIndex,
record,
handleSave,
...restProps
}) => {
const [editing, setEditing] = useState(false);
const inputRef = useRef();
const form = useContext(EditableContext);
useEffect(() => {
if (editing) {
inputRef.current.focus();
}
}, [editing]);
const toggleEdit = () => {
setEditing(!editing);
form.setFieldsValue({
[dataIndex]: record[dataIndex],
});
};
const save = async (e) => {
try {
const values = await form.validateFields();
toggleEdit();
handleSave({ ...record, ...values });
} catch (errInfo) {
console.log('Save failed:', errInfo);
}
};
let childNode = children;
if (editable) {
childNode = editing ? (
<Form.Item
style={{
margin: 0,
}}
name={dataIndex}
rules={[
{
required: true,
message: `${title} is required.`,
},
]}
>
<Input ref={inputRef} onPressEnter={save} onBlur={save} />
</Form.Item>
) : (
<div
className="editable-cell-value-wrap"
style={{
paddingRight: 24,
}}
onClick={toggleEdit}
>
{children}
</div>
);
}
return <td {...restProps}>{childNode}</td>;
};
const ReportDemo = ({ data = myData }) => {
const [pageNum, setPageNum] = useState(1);
const [dataSource, setDataSource] = useState(data.myData);
const [count, setCount] = useState(2);
const handleDelete = (key) => {
setDataSource(dataSource.filter((item) => item.key !== key));
};
const handleAdd = () => {
const newData = {
key: count + 10,
name: `Edward King ${count}`,
age: 32,
address: `London, Park Lane no. ${count}`,
};
setDataSource([...dataSource, newData]);
setCount((c) => c + 1);
};
const handleSave = (row) => {
const newData = [...dataSource];
const index = newData.findIndex((item) => row.key === item.key);
const item = newData[index];
newData.splice(index, 1, { ...item, ...row });
setDataSource(newData);
};
const components = {
body: {
row: EditableRow,
cell: EditableCell,
},
};
return (
<div style={{ flex: 1 }}>
<Button
onClick={handleAdd}
type="primary"
style={{
marginBottom: 16,
}}
>
Add a row
</Button>
<Table
dataSource={dataSource}
style={{ height: '100%' }}
scroll={{ x: '50vw' }}
sticky
pagination={{
position: ['bottomLeft'],
total: dataSource.length,
defaultPageSize: 5,
current: pageNum,
onChange: setPageNum,
}}
components={components}
loading={false}
>
<Column
width={'10vw'}
fixed="left"
title="name"
dataIndex="name"
key="name"
onFilter={(value, record) => record.name.indexOf(value) !== -1}
filters={[
{
text: 'Joe',
value: 'Joe',
},
{
text: 'Jim',
value: 'Jim',
},
{
text: 'Submenu',
value: 'Submenu',
children: [
{
text: 'Green',
value: 'Green',
},
{
text: 'Black',
value: 'Black',
},
],
},
]}
onCell={(record) => ({
record,
editable: true,
dataIndex: 'name',
title: 'name',
handleSave: handleSave,
})}
/>
<Column width={'20vw'} title="a" dataIndex="a" key="a"></Column>
<Column width={'20vw'} title="b" dataIndex="b" key="b"></Column>
<Column width={'20vw'} title="c" dataIndex="c" key="c"></Column>
<Column width={'20vw'} title="d" dataIndex="d" key="d"></Column>
<Column width={'20vw'} title="e" dataIndex="e" key="e"></Column>
<Column
title="Address"
dataIndex="address"
key="address"
width={'20vw'}
/>
<Column
width={'10vw'}
fixed="right"
title="Age"
dataIndex="age"
key="age"
sorter={(a, b) => a.age - b.age}
defaultSortOrder={'descend'}
filters={[
{ text: '三十二', value: 32 },
{ text: '四十二', value: 42 },
]}
onFilter={(value, record) => record.age === value}
/>
<Column
width={'10vw'}
fixed="right"
title="operation"
dataIndex="operation"
render={(text, record) =>
dataSource.length >= 1 ? (
<Popconfirm
title="Sure to delete?"
onConfirm={() => handleDelete(record.key)}
>
<a>Delete</a>
</Popconfirm>
) : null
}
></Column>
</Table>
</div>
);
};
export default ReportDemo;
//function component vs class component
// 1. 狀態的使用方法
// => 使用state時候 不用使用this
// => 使用更改狀態的方法時 不用使用this
// => state改用useState 而不是用在constructor
// 2. 方法的呼叫
// => 使用方法時, 不用this
import React, { useContext, useState, useEffect, useRef } from 'react';
import { Table, Input, Button, Popconfirm, Form } from 'antd';
import reqwest from 'reqwest';
const myData = {
myData: [
{
key: '1',
name: 'John Brown',
a: '1',
b: '2',
c: '3',
d: '4',
e: '5',
age: 32,
address: 'New York No. 1 Lake Park',
},
{
key: '2',
name: 'Jim Green',
a: '1',
b: '2',
c: '3',
d: '4',
e: '5',
age: 42,
address: 'London No. 1 Lake Park',
},
{
key: '3',
name: 'Joe Black',
a: '1',
b: '2',
c: '3',
d: '4',
e: '5',
age: 32,
address: 'Sidney No. 1 Lake Park',
},
{
key: '4',
name: 'Jim Red',
a: '1',
b: '2',
c: '3',
d: '4',
e: '5',
age: 32,
address: 'London No. 2 Lake Park',
},
],
};
const { Column, ColumnGroup } = Table;
const EditableContext = React.createContext();
const EditableRow = ({ index, ...props }) => {
const [form] = Form.useForm();
return (
<Form form={form} component={false}>
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
</Form>
);
};
const EditableCell = ({
title,
editable,
children,
dataIndex,
record,
handleSave,
...restProps
}) => {
const [editing, setEditing] = useState(false);
const inputRef = useRef();
const form = useContext(EditableContext);
useEffect(() => {
if (editing) {
inputRef.current.focus();
}
}, [editing]);
const toggleEdit = () => {
setEditing(!editing);
form.setFieldsValue({
[dataIndex]: record[dataIndex],
});
};
const save = async (e) => {
try {
const values = await form.validateFields();
toggleEdit();
handleSave({ ...record, ...values });
} catch (errInfo) {
console.log('Save failed:', errInfo);
}
};
let childNode = children;
if (editable) {
childNode = editing ? (
<Form.Item
style={{
margin: 0,
}}
name={dataIndex}
rules={[
{
required: true,
message: `${title} is required.`,
},
]}
>
<Input ref={inputRef} onPressEnter={save} onBlur={save} />
</Form.Item>
) : (
<div
className="editable-cell-value-wrap"
style={{
paddingRight: 24,
}}
onClick={toggleEdit}
>
{children}
</div>
);
}
return <td {...restProps}>{childNode}</td>;
};
const ReportDemo = () => {
const [pageNum, setPageNum] = useState(1);
const [dataSource, setDataSource] = useState([]);
const [count, setCount] = useState(2);
const [pagination, setPagination] = useState({
current: 1,
pageSize: 10,
});
const [loading, setLoading] = useState(false);
useEffect(() => {
fetchData({ pagination });
}, []);
const handleDelete = (key) => {
setDataSource(dataSource.filter((item) => item.key !== key));
};
const handleAdd = () => {
const newData = {
key: count + 10,
name: `Edward King ${count}`,
age: 32,
address: `London, Park Lane no. ${count}`,
};
setDataSource([...dataSource, newData]);
setCount((c) => c + 1);
};
const handleSave = (row) => {
const newData = [...dataSource];
const index = newData.findIndex((item) => row.key === item.key);
const item = newData[index];
newData.splice(index, 1, { ...item, ...row });
setDataSource(newData);
};
const getRandomuserParams = (params) => {
return {
results: params.pagination.pageSize,
page: params.pagination.current,
...params,
};
};
const handleTableChange = (pagination, filters, sorter) => {
console.log('handleTableChange', pagination);
fetchData({
sortField: sorter.field,
sortOrder: sorter.order,
pagination,
...filters,
});
};
const fetchData = (params = {}) => {
setLoading(true);
reqwest({
url: 'https://cors-anywhere.herokuapp.com/https://randomuser.me/api',
method: 'get',
type: 'json',
data: getRandomuserParams(params),
}).then((data) => {
setLoading(false);
setPagination({ ...params.pagination, total: 200 });
setDataSource(data.results);
});
};
const components = {
body: {
row: EditableRow,
cell: EditableCell,
},
};
return (
<div style={{ flex: 1 }}>
<Button
onClick={handleAdd}
type="primary"
style={{
marginBottom: 16,
}}
>
Add a row
</Button>
<Table
dataSource={dataSource}
style={{ height: '100%' }}
scroll={{ x: '50vw' }}
sticky
pagination={pagination}
components={components}
loading={loading}
onChange={handleTableChange}
rowKey={(record) => record.login.uuid}
>
<Column
width={'10vw'}
fixed="left"
title="name"
dataIndex="name"
key="name"
onFilter={(value, record) => record.name.indexOf(value) !== -1}
filters={[
{
text: 'Joe',
value: 'Joe',
},
{
text: 'Jim',
value: 'Jim',
},
{
text: 'Submenu',
value: 'Submenu',
children: [
{
text: 'Green',
value: 'Green',
},
{
text: 'Black',
value: 'Black',
},
],
},
]}
onCell={(record) => ({
record,
editable: true,
dataIndex: 'name',
title: 'name',
handleSave: handleSave,
})}
render={(name) => `${name.first} ${name.last}`}
/>
<Column
width={'20vw'}
title="Email"
dataIndex="email"
key="email"
></Column>
<Column
width={'20vw'}
title="Gender"
dataIndex="gender"
key="gender"
filters={[
{ text: 'Male', value: 'male' },
{ text: 'Female', value: 'female' },
]}
></Column>
<Column width={'20vw'} title="a" dataIndex="a" key="a"></Column>
<Column width={'20vw'} title="b" dataIndex="b" key="b"></Column>
<Column width={'20vw'} title="c" dataIndex="c" key="c"></Column>
<Column width={'20vw'} title="d" dataIndex="d" key="d"></Column>
<Column width={'20vw'} title="e" dataIndex="e" key="e"></Column>
<Column
title="Address"
dataIndex="address"
key="address"
width={'20vw'}
/>
<Column
width={'10vw'}
fixed="right"
title="Age"
dataIndex="age"
key="age"
sorter={(a, b) => a.age - b.age}
defaultSortOrder={'descend'}
filters={[
{ text: '三十二', value: 32 },
{ text: '四十二', value: 42 },
]}
onFilter={(value, record) => record.age === value}
/>
<Column
width={'10vw'}
fixed="right"
title="operation"
dataIndex="operation"
render={(text, record) =>
dataSource.length >= 1 ? (
<Popconfirm
title="Sure to delete?"
onConfirm={() => handleDelete(record.key)}
>
<a>Delete</a>
</Popconfirm>
) : null
}
></Column>
</Table>
</div>
);
};
export default ReportDemo;
//function component vs class component
// 1. 狀態的使用方法
// => 使用state時候 不用使用this
// => 使用更改狀態的方法時 不用使用this
// => state改用useState 而不是用在constructor
// 2. 方法的呼叫
// => 使用方法時, 不用this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment