系统中的若干个页面须要展现表格数据,其中某些表格数据过多须要分页查询,而某些不用。javascript
components: TableDisplay.jsx Pagination.jsx containers: TableContainer.jsx
TableDisplay
:表格数据展现组件,参数以下:Pagination
:用于展现分页的组件,参数以下:TableContainer
:封装分页控制、加载表格数据等业务逻辑的容器型组件首先看下不使用hooks,使用传统的Class组件封装业务逻辑的代码:java
import React from 'react';
import TableDisplay from 'components/TableDisplay';
import Pagination from 'components/Pagination';
import { getTableData } from 'apis'; //获取表格数据的api
export default class TableContainer extends React.Component {
state = {
data: {
tableData: [],
total: 0,
},
pagination: {
page: 1,
pageSize: 10
},
loading: false
}
componentDidMount() {
// 首次加载时默认查询第一页数据
this.loadTable();
}
handlePageChange: (page) => {
this.setState({
pagination: {
...this.state.pagination, page
}
});
this.loadTable();
}
handlePageSizeChange: (pageSize) => {
this.setState({
pagination: {
page: 1, //pageSize改变时,page自动跳到1
pageSize
}
});
this.loadTable();
}
loadTable: () => {
this.setState({
loading:true
});
// 调用APi获取数据
getTableData(this.state.pagination)
.then(({data}) => {
// 数据加载成功
this.setState({
data
});
})
.catch(error => {
console.log(error);
})
.finally(() => {
this.setState({
loading: false
});
});
}
render() {
const {data, pagination, loading} = this.state;
return (
<div>
<TableDisplay data={ data.tableData } loading={ loading } />
<Pagination
onPageChange={ this.handlePageChange }
onPageSizeChange={ this.handlePageSizeChange }
total={ data.total }
{ ...pagination } />
</div>
);
}
}
复制代码
使用Class组件使得业务逻辑代码难以分割和复用;react
import React, { useState, useEffect } from 'react';
import TableDisplay from 'components/TableDisplay';
import Pagination from 'components/Pagination';
import { getTableData } from 'apis'; //获取表格数据的api
export default () => {
// 表格数据
const [data, setData] = useState({
tableData: [],
total: 0
});
// 分页状态
const [pagination, setPagination] = useState({
page: 1,
pageSize: 10
});
// 加载状态
const [loading, setLoading] = useState(false);
useEffect(() => { //分页状态改变时,加载数据
setLoading(true);
getTableData(pagination)
.then(data => {
setTableData({
total: data.total,
data: data.data
});
})
.catch(error => {
console.log(error);
})
.finally(() => {
setLoading(false);
});
}, pagination);
const handlePageChange = page => setPagination({
page,
pageSize: pagination.pageSize
});
const handlePageSizeChange = pageSize => setPagination({
page: 1,
pageSize
});
return (
<div>
<TableDisplay data={ data.tableData } loading={ loading } />
<Pagination
onPageChange={ handlePageChange }
onPageSizeChange={ handlePageSizeChange }
total={ data.total }
{ ...pagination } />
</div>
);
}
复制代码
到这一步,还没达到抽离可复用逻辑的目的api
为了实现本文第一行中提到的需求,须要将表格数据加载和分页控制分割开来,使得分页这部分功能可插拔。ui
因而须要两个自定义Hookthis
hooks: --useTableDataLoader --usePagination
useTableDataLoader.js
代码以下:import { useState, useEffect } from 'react';
export default (api, pagination) => {
const [data, setData] = useState({
total: 0,
tableData: []
});
const [loading, setLoading] = useState(false);
useEffect(() => {
setLoading(true);
api(pagination)
.then(data => {
setData(data);
})
.catch(error => {
console.log(error)
})
.finally(() => {
setLoading(false);
});
}, pagination);
return {
data, loading
};
}
复制代码
HookuseTableDataLoader
须要两个参数:spa
api
:获取表格数据的apipagination
:分页状态,可选参数,当api不须要时可不传入,表格只会加载一次返回一个对象:code
data
: 请求的数据loading
:是否处于加载状态usePagination.js
代码以下:import { useState } from 'react';
export default () => {
const [pagination, setPagination] = useState({
page: 1,
pageSize: 10
});
return {
pagination,
setPage(page) {
setPagination({
page,
pageSize: pagination.pageSize
});
},
setPageSize(pageSize) {
setPagination({
page: 1,
pageSize
});
}
};
}
复制代码
HookuseTableDataLoader
返回一个对象:component
pagination
:分页信息setPage
:修改当前页码的方法setPageSize
:修改pageSize的方法TableWithPaginationContainer.jsx
代码以下:import React from 'react';
import TableDisplay from 'components/TableDisplay';
import Pagination from 'components/Pagination';
import { getTableData } from 'apis'; //获取表格数据的api
import useTableDataLoader from 'hooks/useTableDataLoader';
import usePagination from 'hooks/usePagination';
export default () => {
const { pagination, setPage, setPageSize } = usePagination();
const { data, loading } = useTableDataLoader(getTableData, pagination);
const { tableData, total } = data;
return (
<div>
<TableDisplay loading={loading} data={tableData}/>
<Pagination
onPageChange={ setPage }
onPageSizeChange={ setPageSize }
total={total}
{ ...pagination } />
</div>
);
}
复制代码
TableContainer.jsx
代码以下:import React from 'react';
import TableDisplay from 'components/TableDisplay';
import { getTableData } from 'apis'; //获取表格数据的api
import useTableDataLoader from 'hooks/useTableDataLoader';
export default () => {
const { data, loading } = useTableDataLoader(getTableData);
const { tableData, total } = data;
return (
<TableDisplay loading={loading} data={tableData}/> ); } 复制代码
这样就实现了可复用逻辑代码的分割和抽离,并使得编写组件的代码更加简介明了!xml