后台管理系统中必定会出现的组件就是表格页面,并且一个系统中往往有多个表格页面。
表格页面的业务逻辑,有许多相似之处,包括:
- 获取数据源
- 刷新数据源
- 分页
- 查询
- loading
因此,我发现在重构之前,每一个表格页面,都有一套几乎一模一样的逻辑:
import { Table } from "antd";
import { mock, Random } from "mockjs";
import React, { useEffect, useState } from "react";
const fetchUsers = (pageIndex, pageSize) => {
return Promise.resolve(
mock({
"total|10-100": pageSize * 5.5,
"list|10": [
{
"name|1": [
Random.name(),
Random.name(),
Random.name(),
Random.name(),
],
"gender|1": ["male", "female"],
},
],
})
);
};
const UserList = () => {
const [isLoading, setIsLoading] = useState(false);
const [dataSource, setDataSource] = useState([]);
const [pageIndex, setPageIndex] = useState(10);
const [pageSize, setPageSize] = useState(10);
const [total, setTotal] = useState(0);
useEffect(() => {
fechDataSource();
}, []);
useEffect(() => {
fechDataSource();
}, [pageSize, pageIndex]);
const fechDataSource = () => {
setIsLoading(true);
fetchUsers(pageIndex, pageSize)
.then((res) => {
setDataSource(res.list);
setTotal(res.total);
})
.catch((error) => {
console.error(error);
})
.finally(() => {
setIsLoading(false);
});
};
const pagination = {
showSizeChanger: true,
showTotal: () => `total: ${total}`,
total,
current: pageIndex,
pageSize,
onChange: (pageIndex, pageSize) => {
setPageIndex(pageIndex);
setPageSize(pageSize);
},
};
const tableProps = {
loading: isLoading,
dataSource,
columns: [
{
title: "Name",
dataIndex: "name",
key: "name",
},
{
title: "Gender",
dataIndex: "gender",
key: "gender",
},
],
pagination,
};
return <Table {...tableProps} />;
};
export default UserList;
针对这个问题,我自定义了一个hook,将公共逻辑抽出来:
import { Table, Button } from "antd";
import { mock, Random } from "mockjs";
import React from "react";
import useTable from "../hooks/useTable";
const fetchUsers = (pageIndex, pageSize) => {
return Promise.resolve(
mock({
"total|10-100": pageSize * 5.5,
"list|10": [
{
"name|1": [
Random.name(),
Random.name(),
Random.name(),
Random.name(),
],
"gender|1": ["male", "female"],
},
],
})
);
};
const columns = [
{
title: "Name",
dataIndex: "name",
key: "name",
},
{
title: "Gender",
dataIndex: "gender",
key: "gender",
},
];
const UserListWithHook = () => {
const { tableProps, query } = useTable(fetchUsers);
const handleRefresh = () => {
query();
};
return (
<div>
<Button onClick={handleRefresh}>Refresh</Button>
<Table columns={columns} {...tableProps} />
</div>
);
};
export default UserListWithHook;
import { useEffect, useState } from "react";
import useAsync from "./useAsync";
const useTable = (fetchDataSource = () => Promise.resolve([])) => {
const [params, setParams] = useState({
pageSize: 10,
pageIndex: 1,
});
const {
res = {},
isLoading,
query,
} = useAsync((originParams = {}) =>
fetchDataSource({ ...params, ...originParams })
);
useEffect(() => {
query(params);
}, [params]);
const pagination = {
current: params.pageIndex,
pageSize: params.pageSize,
onChange: (index, pageSize) => {
setParams({
...params,
pageIndex: index,
pageSize: pageSize || params.pageSize,
});
},
};
const tableProps = {
dataSource: res.list,
pagination,
loading: isLoading,
};
return {
tableProps,
query,
params,
};
};
export default useTable;
用上自定义Hook useTable之后,UserList组件就清爽多了。
在usetTable中,还嵌套使用了另一个自定义hook,也就是useAsync,关于这个自定义组件的详细内容见https://www.jianshu.com/p/7b6f3aaa1a27?v=1667120684038