fix: 4.0 table filters value may be previous (#19873)

* fix: 4.0 table filters value may be previous

* create a sync variable to resolve async 'setFilteredKeys'

* useSyncState to fix 'setFilteredKeys' async

* new line

* new line

* add ,

* removed 'setFilteredKeys' and re-render useSyncState

* menu must be a array
This commit is contained in:
jeessy2 2019-11-26 14:25:33 +08:00 committed by 二货机器人
parent 5fc62314af
commit 221d404986
4 changed files with 48 additions and 10 deletions

View File

@ -123,6 +123,15 @@ describe('Table.filter', () => {
<span onClick={() => clearFilters()} id="reset">
Reset
</span>
<span
onClick={() => {
setSelectedKeys([43]);
confirm();
}}
id="simulateOnSelect"
>
SimulateOnSelect
</span>
</div>
);
@ -170,6 +179,11 @@ describe('Table.filter', () => {
.first()
.props().visible,
).toBeFalsy();
// Simulate onSelect, setSelectedKeys & confirm
wrapper.find('span.ant-dropdown-trigger').simulate('click', nativeEvent);
wrapper.find('#simulateOnSelect').simulate('click');
expect(getFilterMenu().props().filterState.filteredKeys).toEqual([43]);
});
it('can be controlled by filterDropdownVisible', () => {

View File

@ -23,6 +23,12 @@ exports[`Table.filter override custom filter correctly 1`] = `
>
Reset
</span>
<span
id="simulateOnSelect"
onClick={[Function]}
>
SimulateOnSelect
</span>
</div>
`;

View File

@ -9,6 +9,7 @@ import Dropdown from '../../../dropdown';
import { ColumnType, ColumnFilterItem, Key, TableLocale, GetPopupContainer } from '../../interface';
import FilterDropdownMenuWrapper from './FilterWrapper';
import { FilterState } from '.';
import useSyncState from '../useSyncState';
const { SubMenu, Item: MenuItem } = Menu;
@ -91,21 +92,21 @@ function FilterDropdown<RecordType>(props: FilterDropdownProps<RecordType>) {
const [propFilteredKeys, setPropFilteredKeys] = React.useState(
filterState && filterState.filteredKeys,
);
const [filteredKeys, setFilteredKeys] = React.useState(propFilteredKeys || []);
const [getFilteredKeysSync, setFilteredKeysSync] = useSyncState(propFilteredKeys || []);
const onSelectKeys = ({ selectedKeys }: { selectedKeys: Key[] }) => {
setFilteredKeysSync(selectedKeys);
};
React.useEffect(() => {
// Sync internal filtered keys when props key changed
const newFilteredKeys = filterState && filterState.filteredKeys;
if (!shallowEqual(propFilteredKeys, newFilteredKeys)) {
setPropFilteredKeys(newFilteredKeys);
setFilteredKeys(newFilteredKeys || []);
onSelectKeys({ selectedKeys: newFilteredKeys || [] });
}
}, [filterState]);
const onSelectKeys = ({ selectedKeys }: { selectedKeys: Key[] }) => {
setFilteredKeys(selectedKeys);
};
// ====================== Open Keys ======================
const [openKeys, setOpenKeys] = React.useState<string[]>([]);
const openRef = React.useRef<number>();
@ -140,7 +141,7 @@ function FilterDropdown<RecordType>(props: FilterDropdownProps<RecordType>) {
};
const onConfirm = () => {
internalTriggerFilter(filteredKeys);
internalTriggerFilter(getFilteredKeysSync());
};
const onReset = () => {
@ -167,7 +168,7 @@ function FilterDropdown<RecordType>(props: FilterDropdownProps<RecordType>) {
dropdownContent = column.filterDropdown({
prefixCls: `${dropdownPrefixCls}-custom`,
setSelectedKeys: (selectedKeys: Key[]) => onSelectKeys({ selectedKeys }),
selectedKeys: filteredKeys,
selectedKeys: getFilteredKeysSync(),
confirm: onConfirm,
clearFilters: onReset,
filters: column.filters,
@ -185,12 +186,12 @@ function FilterDropdown<RecordType>(props: FilterDropdownProps<RecordType>) {
onClick={onMenuClick}
onSelect={onSelectKeys}
onDeselect={onSelectKeys}
selectedKeys={(filteredKeys || []) as any}
selectedKeys={(getFilteredKeysSync() || []) as any}
getPopupContainer={getPopupContainer}
openKeys={openKeys}
onOpenChange={onOpenChange}
>
{renderFilterItems(column.filters!, prefixCls, filteredKeys, filterMultiple)}
{renderFilterItems(column.filters!, prefixCls, getFilteredKeysSync(), filterMultiple)}
</Menu>
<div className={`${prefixCls}-dropdown-btns`}>
<a className={`${prefixCls}-dropdown-link confirm`} onClick={onConfirm}>

View File

@ -0,0 +1,17 @@
import * as React from 'react';
type UseSyncStateProps<T> = [() => T, (newValue: T) => void];
export default function useSyncState<T>(filteredKeys: T): UseSyncStateProps<T> {
const filteredKeysRef = React.useRef<T>(filteredKeys);
const [, forceUpdate] = React.useState<T>();
return [
() => filteredKeysRef.current,
(newValue: T) => {
filteredKeysRef.current = newValue;
// re-render
forceUpdate(filteredKeys);
},
];
}