implement pagination context

This commit is contained in:
AllenFang
2018-05-20 16:35:35 +08:00
parent 1e72c80566
commit 6c086c3892
6 changed files with 179 additions and 106 deletions

View File

@@ -1,6 +1,6 @@
import wrapperFactory from './src/wrapper';
import createContext from './src/context';
export default (options = {}) => ({
wrapperFactory,
createContext,
options
});

View File

@@ -1,17 +1,21 @@
/* eslint react/prop-types: 0 */
import React, { Component } from 'react';
/* eslint react/require-default-props: 0 */
import React from 'react';
import PropTypes from 'prop-types';
import Const from './const';
import Pagination from './pagination';
import { getByCurrPage, alignPage } from './page';
export default (Base, {
remoteResolver
}) =>
class PaginationWrapper extends remoteResolver(Component) {
export default (
isRemotePagination,
handleRemotePageChange
) => {
const PaginationContext = React.createContext();
class PaginationProvider extends React.Component {
static propTypes = {
store: PropTypes.object.isRequired
data: PropTypes.array.isRequired
}
constructor(props) {
@@ -42,13 +46,13 @@ export default (Base, {
currSizePerPage = sizePerPageList[0];
}
this.state = { currPage, currSizePerPage };
this.saveToStore(currPage, currSizePerPage);
this.currPage = currPage;
this.currSizePerPage = currSizePerPage;
}
componentWillReceiveProps(nextProps) {
let needNewState = false;
let { currPage, currSizePerPage } = this.state;
let { currPage, currSizePerPage } = this;
const { page, sizePerPage, onPageChange } = nextProps.pagination.options;
const pageStartIndex = typeof nextProps.pagination.options.pageStartIndex !== 'undefined' ?
@@ -57,70 +61,64 @@ export default (Base, {
if (typeof page !== 'undefined' && currPage !== page) { // user defined page
currPage = page;
needNewState = true;
} else if (nextProps.isDataChanged) {
currPage = alignPage(this.props.store, pageStartIndex, currSizePerPage);
} else {
currPage = alignPage(nextProps.data, currPage, currSizePerPage, pageStartIndex);
needNewState = true;
}
if (typeof currPage === 'undefined') {
currPage = pageStartIndex;
}
if (typeof sizePerPage !== 'undefined') {
if (typeof sizePerPage !== 'undefined' && currSizePerPage !== sizePerPage) {
currSizePerPage = sizePerPage;
needNewState = true;
}
this.saveToStore(currPage, currSizePerPage);
if (needNewState) {
if (onPageChange) {
onPageChange(currPage, currSizePerPage);
}
this.setState(() => ({ currPage, currSizePerPage }));
this.currPage = currPage;
this.currSizePerPage = currSizePerPage;
}
}
saveToStore(page, sizePerPage) {
this.props.store.page = page;
this.props.store.sizePerPage = sizePerPage;
}
handleChangePage(currPage) {
const { currSizePerPage } = this.state;
const { currSizePerPage } = this;
const { pagination: { options } } = this.props;
this.saveToStore(currPage, currSizePerPage);
if (options.onPageChange) {
options.onPageChange(currPage, currSizePerPage);
}
if (this.isRemotePagination()) {
this.handleRemotePageChange();
this.currPage = currPage;
if (isRemotePagination()) {
handleRemotePageChange(currPage, currSizePerPage);
return;
}
this.setState(() => ({ currPage }));
this.forceUpdate();
}
handleChangeSizePerPage(currSizePerPage, currPage) {
const { pagination: { options } } = this.props;
this.saveToStore(currPage, currSizePerPage);
if (options.onSizePerPageChange) {
options.onSizePerPageChange(currSizePerPage, currPage);
}
if (this.isRemotePagination()) {
this.handleRemotePageChange();
this.currPage = currPage;
this.currSizePerPage = currSizePerPage;
if (isRemotePagination()) {
handleRemotePageChange(currPage, currSizePerPage);
return;
}
this.setState(() => ({
currPage,
currSizePerPage
}));
this.forceUpdate();
}
render() {
const { pagination: { options }, store } = this.props;
const { currPage, currSizePerPage } = this.state;
let { data } = this.props;
const { pagination: { options } } = this.props;
const { currPage, currSizePerPage } = this;
const withFirstAndLast = typeof options.withFirstAndLast === 'undefined' ?
Const.With_FIRST_AND_LAST : options.withFirstAndLast;
const alwaysShowAllBtns = typeof options.alwaysShowAllBtns === 'undefined' ?
@@ -132,37 +130,50 @@ export default (Base, {
const pageStartIndex = typeof options.pageStartIndex === 'undefined' ?
Const.PAGE_START_INDEX : options.pageStartIndex;
const data = this.isRemotePagination() ?
this.props.data :
getByCurrPage(store, pageStartIndex);
data = isRemotePagination() ?
data :
getByCurrPage(
data,
currPage,
currSizePerPage,
pageStartIndex
);
return [
<Base key="table" { ...this.props } data={ data } />,
<Pagination
key="pagination"
dataSize={ options.totalSize || store.data.length }
currPage={ currPage }
currSizePerPage={ currSizePerPage }
onPageChange={ this.handleChangePage }
onSizePerPageChange={ this.handleChangeSizePerPage }
sizePerPageList={ options.sizePerPageList || Const.SIZE_PER_PAGE_LIST }
paginationSize={ options.paginationSize || Const.PAGINATION_SIZE }
pageStartIndex={ pageStartIndex }
withFirstAndLast={ withFirstAndLast }
alwaysShowAllBtns={ alwaysShowAllBtns }
hideSizePerPage={ hideSizePerPage }
hidePageListOnlyOnePage={ hidePageListOnlyOnePage }
showTotal={ options.showTotal }
paginationTotalRenderer={ options.paginationTotalRenderer }
firstPageText={ options.firstPageText || Const.FIRST_PAGE_TEXT }
prePageText={ options.prePageText || Const.PRE_PAGE_TEXT }
nextPageText={ options.nextPageText || Const.NEXT_PAGE_TEXT }
lastPageText={ options.lastPageText || Const.LAST_PAGE_TEXT }
prePageTitle={ options.prePageTitle || Const.PRE_PAGE_TITLE }
nextPageTitle={ options.nextPageTitle || Const.NEXT_PAGE_TITLE }
firstPageTitle={ options.firstPageTitle || Const.FIRST_PAGE_TITLE }
lastPageTitle={ options.lastPageTitle || Const.LAST_PAGE_TITLE }
/>
];
return (
<PaginationContext.Provider value={ { data } }>
{ this.props.children }
<Pagination
key="pagination"
dataSize={ options.totalSize || this.props.data.length }
currPage={ currPage }
currSizePerPage={ currSizePerPage }
onPageChange={ this.handleChangePage }
onSizePerPageChange={ this.handleChangeSizePerPage }
sizePerPageList={ options.sizePerPageList || Const.SIZE_PER_PAGE_LIST }
paginationSize={ options.paginationSize || Const.PAGINATION_SIZE }
pageStartIndex={ pageStartIndex }
withFirstAndLast={ withFirstAndLast }
alwaysShowAllBtns={ alwaysShowAllBtns }
hideSizePerPage={ hideSizePerPage }
hidePageListOnlyOnePage={ hidePageListOnlyOnePage }
showTotal={ options.showTotal }
paginationTotalRenderer={ options.paginationTotalRenderer }
firstPageText={ options.firstPageText || Const.FIRST_PAGE_TEXT }
prePageText={ options.prePageText || Const.PRE_PAGE_TEXT }
nextPageText={ options.nextPageText || Const.NEXT_PAGE_TEXT }
lastPageText={ options.lastPageText || Const.LAST_PAGE_TEXT }
prePageTitle={ options.prePageTitle || Const.PRE_PAGE_TITLE }
nextPageTitle={ options.nextPageTitle || Const.NEXT_PAGE_TITLE }
firstPageTitle={ options.firstPageTitle || Const.FIRST_PAGE_TITLE }
lastPageTitle={ options.lastPageTitle || Const.LAST_PAGE_TITLE }
/>
</PaginationContext.Provider>
);
}
}
return {
Provider: PaginationProvider,
Consumer: PaginationContext.Consumer
};
};

View File

@@ -1,5 +1,3 @@
/* eslint no-param-reassign: 0 */
const getNormalizedPage = (
page,
pageStartIndex
@@ -19,25 +17,36 @@ const startIndex = (
sizePerPage,
) => end - (sizePerPage - 1);
export const alignPage = (store, pageStartIndex, sizePerPage) => {
const end = endIndex(store.page, sizePerPage, pageStartIndex);
const dataSize = store.data.length;
export const alignPage = (
data,
page,
sizePerPage,
pageStartIndex
) => {
const end = endIndex(page, sizePerPage, pageStartIndex);
const dataSize = data.length;
if (end - 1 > dataSize) {
return pageStartIndex;
}
return store.page;
return page;
};
export const getByCurrPage = (store, pageStartIndex) => {
const dataSize = store.data.length;
export const getByCurrPage = (
data,
page,
sizePerPage,
pageStartIndex
) => {
const dataSize = data.length;
if (!dataSize) return [];
const end = endIndex(store.page, store.sizePerPage, pageStartIndex);
const start = startIndex(end, store.sizePerPage);
const end = endIndex(page, sizePerPage, pageStartIndex);
const start = startIndex(end, sizePerPage);
const result = [];
for (let i = start; i <= end; i += 1) {
result.push(store.data[i]);
result.push(data[i]);
if (i + 1 === dataSize) break;
}
return result;

View File

@@ -16,8 +16,9 @@ export default () => {
this.setState(() => ({ data: nextProps.data }));
}
getData = (filterProps, sortProps) => {
if (sortProps) return sortProps.data;
getData = (filterProps, sortProps, paginationProps) => {
if (paginationProps) return paginationProps.data;
else if (sortProps) return sortProps.data;
else if (filterProps) return filterProps.data;
return this.props.data;
}

View File

@@ -14,6 +14,7 @@ const withContext = (Base) => {
let CellEditContext;
let SortContext;
let FilterContext;
let PaginationContext;
return class BootstrapTableContainer extends remoteResolver(Component) {
constructor(props) {
@@ -37,6 +38,11 @@ const withContext = (Base) => {
FilterContext = props.filter.createContext(
_, this.isRemoteFiltering, this.handleRemoteFilterChange);
}
if (props.pagination) {
PaginationContext = props.pagination.createContext(
this.isRemotePagination, this.handleRemotePageChange);
}
}
componentWillReceiveProps(nextProps) {
@@ -51,6 +57,7 @@ const withContext = (Base) => {
cellEditProps,
filterProps,
sortProps,
paginationProps,
selectionProps
) => (
<Base
@@ -59,7 +66,8 @@ const withContext = (Base) => {
{ ...sortProps }
{ ...cellEditProps }
{ ...filterProps }
data={ rootProps.getData(filterProps, sortProps) }
{ ...paginationProps }
data={ rootProps.getData(filterProps, sortProps, paginationProps) }
/>
);
}
@@ -69,12 +77,13 @@ const withContext = (Base) => {
rootProps,
cellEditProps,
filterProps,
sortProps
sortProps,
paginationProps
) => (
<SelectionContext.Provider
{ ...baseProps }
selectRow={ this.props.selectRow }
data={ rootProps.getData(filterProps, sortProps) }
data={ rootProps.getData(filterProps, sortProps, paginationProps) }
>
<SelectionContext.Consumer>
{
@@ -83,6 +92,7 @@ const withContext = (Base) => {
cellEditProps,
filterProps,
sortProps,
paginationProps,
selectionProps
)
}
@@ -91,6 +101,33 @@ const withContext = (Base) => {
);
}
renderWithPaginationCtx(base) {
return (
rootProps,
cellEditProps,
filterProps,
sortProps
) => (
<PaginationContext.Provider
ref={ n => this.paginationContext = n }
pagination={ this.props.pagination }
data={ rootProps.getData(filterProps, sortProps) }
>
<PaginationContext.Consumer>
{
paginationProps => base(
rootProps,
cellEditProps,
filterProps,
sortProps,
paginationProps
)
}
</PaginationContext.Consumer>
</PaginationContext.Provider>
);
}
renderWithSortCtx(base, baseProps) {
return (
rootProps,
@@ -167,6 +204,10 @@ const withContext = (Base) => {
base = this.renderWithSelectionCtx(base, baseProps);
}
if (PaginationContext) {
base = this.renderWithPaginationCtx(base, baseProps);
}
if (SortContext) {
base = this.renderWithSortCtx(base, baseProps);
}

View File

@@ -2,30 +2,41 @@ import _ from '../utils';
export default ExtendBase =>
class RemoteResolver extends ExtendBase {
/* eslint class-methods-use-this: 0 */
getNewestState = (state = {}) => {
// const store = this.store || this.props.store;
// return {
// page: store.page,
// sizePerPage: store.sizePerPage,
// filters: store.filters,
// sortField: store.sortField,
// sortOrder: store.sortOrder,
// data: store.getAllData(),
// ...state
// };
return {
sortOrder: this.sortContext.state.sortOrder,
sortField: this.sortContext.state.sortColumn ?
let sortOrder;
let sortField;
let page;
let sizePerPage;
let filters = {};
if (this.sortContext) {
sortOrder = this.sortContext.state.sortOrder;
sortField = this.sortContext.state.sortColumn ?
this.sortContext.state.sortColumn.dataField :
null,
filters: this.filterContext ? this.filterContext.currFilters : {},
null;
}
if (this.filterContext) {
filters = this.filterContext.currFilters;
}
if (this.paginationContext) {
page = this.paginationContext.currPage;
sizePerPage = this.paginationContext.currSizePerPage;
}
return {
sortOrder,
sortField,
filters,
page,
sizePerPage,
...state,
data: this.props.data
};
}
isRemotePagination() {
isRemotePagination = () => {
const { remote } = this.props;
return remote === true || (_.isObject(remote) && remote.pagination);
}
@@ -45,8 +56,8 @@ export default ExtendBase =>
return remote === true || (_.isObject(remote) && remote.cellEdit);
}
handleRemotePageChange() {
this.props.onTableChange('pagination', this.getNewestState());
handleRemotePageChange = (page, sizePerPage) => {
this.props.onTableChange('pagination', this.getNewestState({ page, sizePerPage }));
}
handleRemoteFilterChange = (filters) => {