Skip to content

Commit

Permalink
feat(table): support sorter and filter controll
Browse files Browse the repository at this point in the history
  • Loading branch information
lihang committed May 27, 2021
1 parent 75abb96 commit e739ff5
Show file tree
Hide file tree
Showing 11 changed files with 142 additions and 50 deletions.
2 changes: 1 addition & 1 deletion src/components/table/FilterPopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const FilterPopover = (props: FilterPopoverProps): React.ReactElement => {

useEffect(() => {
setSelectFilterKeys(values);
}, [values]);
}, [values, visible]);

return (
<Popover
Expand Down
3 changes: 2 additions & 1 deletion src/components/table/Table.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { TableScroll } from './demo/TableScroll.stories';
import { TableEmpty } from './demo/TableEmpty.stories';
import { TableLoading } from './demo/TableLoading.stories';
import { TablePagination } from './demo/TablePagination.stories';
import { ControlledTable } from './demo/TableControlled.stories'

export default {
title: 'Functional Components/Table',
Expand All @@ -20,4 +21,4 @@ export default {
},
} as Meta;

export { Base, TableHeader, MultiLine, TableScroll, TableEmpty, TableLoading, TablePagination };
export { Base, TableHeader, MultiLine, TableScroll, TableEmpty, TableLoading, TablePagination, ControlledTable };
15 changes: 9 additions & 6 deletions src/components/table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import usePagination from './hook/usePagination';
import useSelection, { getRowKey } from './hook/useSelection';
import useEllipsisTooltip from './hook/useEllipsisTooltip';
import Title from './Title';
import { TableProps, ColumnsType } from './interface';
import { TableProps, ColumnsType, OnTriggerStateUpdateProps } from './interface';
import Empty from '../empty';
import { translateInnerColumns } from './utils';
import Loading from '../loading';
Expand Down Expand Up @@ -53,8 +53,8 @@ function Table <RecordType>(
const debounceLoading = useDebounceLoading(loading, 1000);
const onHackRow = useHackOnRow(onRow, hackRowEvent);
const innerColumns = useMemo(() => translateInnerColumns(columns), [columns]);
const [activeSorterStates, updateSorterStates, sortedData] = useSorter(innerColumns, dataSource);
const [activeFilterStates, updateFilterStates, filtedData] = useFilter(innerColumns, sortedData);
const [activeSorterStates, updateSorterStates, sortedData, sorter] = useSorter(innerColumns, dataSource);
const [activeFilterStates, updateFilterStates, filtedData, filters] = useFilter(innerColumns, sortedData);
const [
transformShowIndexPipeline,
activePaginationedState,
Expand All @@ -67,9 +67,12 @@ function Table <RecordType>(
});
const [transformEllipsisTooltipPipeline] = useEllipsisTooltip();

const onTriggerStateUpdate = (paginationState = activePaginationedState): void => {
// 分页状态更新的时候,通过 activePaginationedState 拿不到最新的状态。
onChange?.(paginationState, activeSorterStates, activeFilterStates);
const onTriggerStateUpdate = ({
paginationState = activePaginationedState,
sorterState = sorter,
filterStates = filters
}: OnTriggerStateUpdateProps<RecordType>): void => {
onChange?.(paginationState, filterStates, sorterState);
};

const renderTitle = (_columns: ColumnsType<RecordType>): ColumnsType<RecordType> =>
Expand Down
10 changes: 3 additions & 7 deletions src/components/table/Title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,8 @@ const Title = <RecordType,>(props: TitleProps<RecordType>): React.ReactElement =
const { sortOrder: sorterOrder } = sorterState;

const handleSorterChange = (): void => {
updateSorterStates({
...sorterState,
sortOrder: getNextSortDirection(sortDirections, sorterOrder),
});
onTriggerStateUpdate();
const changedSorterState = { ...sorterState, sortOrder: getNextSortDirection(sortDirections, sorterOrder) };
onTriggerStateUpdate({ sorterState: updateSorterStates(changedSorterState) });
};
return (
<span className={classNames(`${prefixCls}-column-sorter`)}>
Expand Down Expand Up @@ -64,8 +61,7 @@ const Title = <RecordType,>(props: TitleProps<RecordType>): React.ReactElement =
}
const { filteredKeys, filters } = filterState;
const handleFilterPopoverClick = (newFilteredKeys: string[]): void => {
updateFilterStates({ ...filterState, filteredKeys: newFilteredKeys });
onTriggerStateUpdate();
onTriggerStateUpdate({ filterStates: updateFilterStates({ ...filterState, filteredKeys: newFilteredKeys }) });
};

return (
Expand Down
2 changes: 1 addition & 1 deletion src/components/table/__test__/Table.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ describe('Testing Table', () => {
);
expect(wrapper.exists('.gio-table-pagination')).toBe(true);
wrapper.find('.gio-pagination-item').at(1).simulate('click');
expect(onChange).toBeCalledWith({ current: 2, pageSize: 10 }, [], []);
expect(onChange).toBeCalledWith({ current: 2, pageSize: 10 }, [], {});
});

it('should be render rightly', () => {
Expand Down
71 changes: 71 additions & 0 deletions src/components/table/demo/TableControlled.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React, { useState } from 'react';
import { SortOrder } from '../interface';
import Table from '../index';


const dataSource = Array.from({ length: 1000 }, (_, key) => ({ a: key, b: key, c: key, d: key }));


const ControlledTable = () => {
const [sortOrder, setSortOrder] = useState<SortOrder>(null);
const [sortOrder2, setSortOrder2] = useState<SortOrder>(null);
const [filters, setFilters] = useState<string[]>([]);
const columns = [
{
title: 'A',
dataIndex: 'a',
key: 'a',
sorter: (a: any, b: any) => a.a - b.a,
sortOrder
},
{
title: 'B',
dataIndex: 'b',
key: 'b',
sorter: (a: any, b: any) => a.a - b.a,
sortOrder: sortOrder2
},
{
title: 'C',
dataIndex: 'c',
key: 'c',
filteredValue: filters,
filters: ['奇数', '偶数'],
onFilter: (value: any, record: any) => {
if (value === '奇数') {
return record.c % 2 === 1;
}
if (value === '偶数') {
return record.c % 2 === 0;
}
return false;
},
},
{
title: 'D',
dataIndex: 'd',
key: 'd',
},
];

return (
<Table
dataSource={dataSource}
columns={columns}
onChange={(p, s, f) => {
if(s?.key === 'a') {
setSortOrder(s.sortOrder);
}
if(s?.key === 'b') {
setSortOrder2(s.sortOrder);
}
if(f.c) {
setFilters(f.c)
}
}}
/>
)
}

// eslint-disable-next-line import/prefer-default-export
export { ControlledTable };
19 changes: 12 additions & 7 deletions src/components/table/hook/useFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@ export const collectFilterStates = <RecordType,>(
columns.forEach((column) => {
if (has(column, 'children')) {
filterStates.push(...collectFilterStates(get(column, 'children')));
} else if (column.filters || column.filterDropdown) {
const { key, filters, onFilter, defaultFilteredValue = [] } = column;
} else if (column.filters) {
const { key, filters, onFilter, defaultFilteredValue = [], filteredValue } = column;
filterStates.push(
clone({
column,
key,
filteredKeys: defaultFilteredValue,
filteredKeys: filteredValue ?? defaultFilteredValue,
onFilter,
filters,
isControlled: !isUndefined(filteredValue)
})
);
}
Expand All @@ -30,18 +31,22 @@ export const collectFilterStates = <RecordType,>(
const useFilter = <RecordType,>(
columns: InnerColumnsType<RecordType>,
data: RecordType[]
): [FilterState<RecordType>[], (filterState: FilterState<RecordType>) => void, RecordType[]] => {
): [FilterState<RecordType>[], (filterState: FilterState<RecordType>) => Record<string, string[]>, RecordType[], Record<string, string[]>] => {
// record all filter states
const [filterStates, setFilterStates] = useState<FilterState<RecordType>[]>(collectFilterStates(columns));

const [filters, setFilters] = useState<Record<string, string[]>>({});
useShallowCompareEffect(() => {
setFilterStates(collectFilterStates(columns));
}, [columns]);

// update filter states action
const updateFilterStates = useCallback(
(filterState: FilterState<RecordType>) => {
setFilterStates([...filterStates.filter(({ key }) => key !== filterState.key), filterState]);
const newFilterStates = filterState.isControlled ? filterStates : [...filterStates.filter(({ key }) => key !== filterState.key), filterState];
const newfilters = [...filterStates.filter(({ key }) => key !== filterState.key), filterState].reduce((prev, curr) => Object.assign(prev, { [curr.key]: curr.filteredKeys }), {} as Record<string, string[]>);
setFilterStates(newFilterStates);
setFilters(newfilters);
return newfilters;
},
[filterStates]
);
Expand All @@ -65,7 +70,7 @@ const useFilter = <RecordType,>(
[data, activeFilterStates]
);

return [filterStates, updateFilterStates, filtedData];
return [filterStates, updateFilterStates, filtedData, filters];
};

export default useFilter;
13 changes: 6 additions & 7 deletions src/components/table/hook/usePagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React, { useMemo, useCallback, useEffect } from 'react';
import { isUndefined } from 'lodash';
import usePrefixCls from '../../../utils/hooks/use-prefix-cls';
import Pagination, { PaginationProps } from '../../pagination';
import { ColumnType, ColumnsType, PaginationState } from '../interface';
import { ColumnType, ColumnsType, PaginationState, OnTriggerStateUpdateProps } from '../interface';
import useControlledState from '../../../utils/hooks/useControlledState';

const usePagination = <RecordType,>(
Expand All @@ -14,8 +14,7 @@ const usePagination = <RecordType,>(
(columns: ColumnsType<RecordType>) => ColumnsType<RecordType>,
PaginationState,
RecordType[],
(props: { onTriggerStateUpdate: (paginationState?: PaginationState) => void }) => JSX.Element | null,
// () => void
(props: { onTriggerStateUpdate: (onTriggerStateUpdateProps: OnTriggerStateUpdateProps<RecordType>) => void; }) => JSX.Element | null,
] => {
const { current, pageSize, total, onChange, onShowSizeChange, defaultCurrent = 1, defaultPageSize = 10, ...rest } = pagination || {};
const [controlledCurrent, setControlledCurrent] = useControlledState<number>(current, defaultCurrent);
Expand Down Expand Up @@ -62,10 +61,10 @@ const usePagination = <RecordType,>(
[controlledCurrent, controlledPageSize]
);

const PaginationComponent = ({
onTriggerStateUpdate,
const PaginationComponent = ({
onTriggerStateUpdate
}: {
onTriggerStateUpdate: (paginationState?: PaginationState) => void;
onTriggerStateUpdate: (onTriggerStateUpdateProps: OnTriggerStateUpdateProps<RecordType>) => void;
}) => (
<Pagination
className={`${prefixCls}-pagination`}
Expand All @@ -81,7 +80,7 @@ const usePagination = <RecordType,>(
setControlledCurrent(_page);
setControlledPageSize(_pageSize);
onChange?.(_page, _pageSize);
onTriggerStateUpdate({ current: _page, pageSize: _pageSize });
onTriggerStateUpdate({ paginationState: { current: _page, pageSize: _pageSize }});
}}
{...rest}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/components/table/hook/useSelection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ const useSelection = <RecordType,>(
setLocalSelectedRowKeys(latestLocalSelectedRowKeys);
onChange?.(latestLocalSelectedRowKeys, getSelectRows(latestLocalSelectedRowKeys));
}}
>&nbsp;</Checkbox>
><span/></Checkbox>
</div>
</Tooltip>
);
Expand Down
29 changes: 19 additions & 10 deletions src/components/table/hook/useSorter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ export const collectSortStates = <RecordType,>(columns: InnerColumnsType<RecordT
if (has(column, 'children')) {
sortStates.push(...collectSortStates(get(column, 'children')));
} else if (column.sorter) {
const { key, sortPriorityOrder, sortDirections = ['ascend', 'descend', null] } = column;
const { key, sortPriorityOrder, sortDirections = ['ascend', 'descend', null], sortOrder, defaultSortOrder } = column;
sortStates.push({
column,
key,
sortPriorityOrder,
sortDirections,
sortOrder: column.defaultSortOrder || null,
sortOrder: sortOrder || defaultSortOrder || null,
isControlled: !isUndefined(sortOrder)
});
}
});
Expand All @@ -26,9 +27,10 @@ export const collectSortStates = <RecordType,>(columns: InnerColumnsType<RecordT
const useSorter = <RecordType,>(
columns: InnerColumnsType<RecordType>,
data: RecordType[]
): [SortState<RecordType>[], (sortState: SortState<RecordType>) => void, RecordType[]] => {
): [SortState<RecordType>[], (sortState: SortState<RecordType>) => SortState<RecordType>, RecordType[], SortState<RecordType> | undefined] => {
// record all sorter states
const [sortStates, setSortStates] = useState<SortState<RecordType>[]>(collectSortStates(columns));
const [_sorter, setSorter] = useState<SortState<RecordType>>();

useShallowCompareEffect(() => {
setSortStates(collectSortStates(columns));
Expand All @@ -37,22 +39,25 @@ const useSorter = <RecordType,>(
// update sorter states action
const updateSorterStates = useCallback(
(incomingSortState: SortState<RecordType>) => {
setSorter(incomingSortState);
setSortStates(
sortStates.map((_sortState) => {
const innerSortState = _sortState;
// if updata cloumn have not sortPriorityOrder, clear all active sortOrder state.
if (isUndefined(incomingSortState.sortPriorityOrder)) {
innerSortState.sortOrder = null;
// only update sortOrder which cloumn have not sortPriorityOrder.
} else if (isUndefined(innerSortState.sortPriorityOrder)) {
// if update cloumn haven't sortPriorityOrder, clear all active sortOrder state.
// if update cloumn haven sortPriorityOrder, only update sortOrder which cloumn haven't sortPriorityOrder.
if ((isUndefined(incomingSortState.sortPriorityOrder) || isUndefined(innerSortState.sortPriorityOrder)) && !innerSortState.isControlled) {
innerSortState.sortOrder = null;
}
if (innerSortState.key === incomingSortState.key) {
if(innerSortState.key === incomingSortState.key) {
if(incomingSortState.isControlled) {
return innerSortState;
}
innerSortState.sortOrder = incomingSortState.sortOrder;
}
return innerSortState;
})
);
return incomingSortState;
},
[sortStates]
);
Expand Down Expand Up @@ -80,6 +85,10 @@ const useSorter = <RecordType,>(
} = sorterState;

if (sortOrder && sorter) {
// server sort
if(sorter === true) {
return 0;
}
const compareResult = sorter(record1, record2);

if (compareResult !== 0) {
Expand All @@ -91,7 +100,7 @@ const useSorter = <RecordType,>(
});
}, [activeSortStates, data]);

return [sortStates, updateSorterStates, sortedData];
return [sortStates, updateSorterStates, sortedData, _sorter];
};

export default useSorter;
Loading

0 comments on commit e739ff5

Please sign in to comment.