系統中的若干個頁面須要展現表格數據,其中某些表格數據過多須要分頁查詢,而某些不用。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