From 7b8a41bd5903c2622d19aa0e06ea52f93d5022a5 Mon Sep 17 00:00:00 2001 From: fzaninotto Date: Fri, 16 Oct 2020 15:05:17 +0200 Subject: [PATCH 1/3] Speed up show & hide filter the useListController hook returned show and hide filter functions based on the debounced setFilters function. No need to debounce (and to wait for 500 millisecons) to show or hide a filter! This improves filtering in a noticeable way. --- .../ra-core/src/controller/useListParams.ts | 71 ++++++++++--------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/packages/ra-core/src/controller/useListParams.ts b/packages/ra-core/src/controller/useListParams.ts index 99299c0afd7..e41e92f8a03 100644 --- a/packages/ra-core/src/controller/useListParams.ts +++ b/packages/ra-core/src/controller/useListParams.ts @@ -197,52 +197,55 @@ const useListParams = ({ ); const displayedFilterValues = query.displayedFilters || emptyObject; - const debouncedSetFilters = lodashDebounce( - (newFilters, newDisplayedFilters) => { - let payload = { - filter: removeEmpty(newFilters), - displayedFilters: undefined, - }; - if (newDisplayedFilters) { - payload.displayedFilters = Object.keys( - newDisplayedFilters - ).reduce((filters, filter) => { - return newDisplayedFilters[filter] - ? { ...filters, [filter]: true } - : filters; - }, {}); - } - changeParams({ - type: SET_FILTER, - payload, - }); - }, - debounce - ); + const debouncedSetFilters = lodashDebounce((filter, displayedFilters) => { + changeParams({ + type: SET_FILTER, + payload: { + filter: removeEmpty(filter), + displayedFilters, + }, + }); + }, debounce); const setFilters = useCallback( - (filters, displayedFilters) => - debouncedSetFilters(filters, displayedFilters), + (filter, displayedFilters) => + debouncedSetFilters(filter, displayedFilters), requestSignature // eslint-disable-line react-hooks/exhaustive-deps ); const hideFilter = useCallback((filterName: string) => { - const newFilters = removeKey(filterValues, filterName); - const newDisplayedFilters = { - ...displayedFilterValues, - [filterName]: undefined, - }; - - setFilters(newFilters, newDisplayedFilters); + // we don't use lodash.set() for displayed filters + // to avoid problems with compound filter names (e.g. 'author.name') + const displayedFilters = Object.keys(displayedFilterValues).reduce( + (filters, filter) => { + return filter !== filterName + ? { ...filters, [filter]: true } + : filters; + }, + {} + ); + const filter = removeEmpty(removeKey(filterValues, filterName)); + changeParams({ + type: SET_FILTER, + payload: { filter, displayedFilters }, + }); }, requestSignature); // eslint-disable-line react-hooks/exhaustive-deps const showFilter = useCallback((filterName: string, defaultValue: any) => { - const newFilters = set(filterValues, filterName, defaultValue); - const newDisplayedFilters = { + // we don't use lodash.set() for displayed filters + // to avoid problkems with compound filter names (e.g. 'author.name') + const displayedFilters = { ...displayedFilterValues, [filterName]: true, }; - setFilters(newFilters, newDisplayedFilters); + const filter = set(filterValues, filterName, defaultValue); + changeParams({ + type: SET_FILTER, + payload: { + filter, + displayedFilters, + }, + }); }, requestSignature); // eslint-disable-line react-hooks/exhaustive-deps return [ From e0949d6c409b530da696757e215fdb6f8ae2ca4b Mon Sep 17 00:00:00 2001 From: fzaninotto Date: Fri, 16 Oct 2020 15:58:36 +0200 Subject: [PATCH 2/3] Make FilterListItem use setFilter without debounce --- .../src/controller/useListController.ts | 6 +++++- .../ra-core/src/controller/useListParams.ts | 12 ++++++++++-- .../src/list/filter/FilterListItem.tsx | 18 ++++++++++++------ 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/packages/ra-core/src/controller/useListController.ts b/packages/ra-core/src/controller/useListController.ts index bd87ddb2d24..7f3a2617dd9 100644 --- a/packages/ra-core/src/controller/useListController.ts +++ b/packages/ra-core/src/controller/useListController.ts @@ -73,7 +73,11 @@ export interface ListControllerProps { perPage: number; resource: string; selectedIds: Identifier[]; - setFilters: (filters: any, displayedFilters: any) => void; + setFilters: ( + filters: any, + displayedFilters: any, + debounce?: boolean + ) => void; setPage: (page: number) => void; setPerPage: (page: number) => void; setSort: (sort: string, order?: string) => void; diff --git a/packages/ra-core/src/controller/useListParams.ts b/packages/ra-core/src/controller/useListParams.ts index e41e92f8a03..470bd6025a7 100644 --- a/packages/ra-core/src/controller/useListParams.ts +++ b/packages/ra-core/src/controller/useListParams.ts @@ -208,8 +208,16 @@ const useListParams = ({ }, debounce); const setFilters = useCallback( - (filter, displayedFilters) => - debouncedSetFilters(filter, displayedFilters), + (filter, displayedFilters, debounce = true) => + debounce + ? debouncedSetFilters(filter, displayedFilters) + : changeParams({ + type: SET_FILTER, + payload: { + filter: removeEmpty(filter), + displayedFilters, + }, + }), requestSignature // eslint-disable-line react-hooks/exhaustive-deps ); diff --git a/packages/ra-ui-materialui/src/list/filter/FilterListItem.tsx b/packages/ra-ui-materialui/src/list/filter/FilterListItem.tsx index e38c6ec0fb4..9eb6ac0dc55 100644 --- a/packages/ra-ui-materialui/src/list/filter/FilterListItem.tsx +++ b/packages/ra-ui-materialui/src/list/filter/FilterListItem.tsx @@ -153,14 +153,20 @@ const FilterListItem: FC<{ label: string; value: any }> = props => { ); const addFilter = () => { - setFilters({ ...filterValues, ...value }, null); + setFilters({ ...filterValues, ...value }, null, false); }; + const removeFilter = () => { - const inverseValue = Object.keys(value).reduce((acc, key) => { - acc[key] = undefined; - return acc; - }, {} as any); - setFilters({ ...filterValues, ...inverseValue }, null); + const keysToRemove = Object.keys(value); + const filters = Object.keys(filterValues).reduce( + (acc, key) => + keysToRemove.includes(key) + ? acc + : { ...acc, [key]: filterValues[key] }, + {} + ); + + setFilters(filters, null, false); }; const toggleFilter = () => (isSelected ? removeFilter() : addFilter()); From 3bf25e02c52a72815b4c1174f98ddc8738f82448 Mon Sep 17 00:00:00 2001 From: fzaninotto Date: Fri, 16 Oct 2020 16:08:18 +0200 Subject: [PATCH 3/3] Fix typo in comment --- packages/ra-core/src/controller/useListParams.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ra-core/src/controller/useListParams.ts b/packages/ra-core/src/controller/useListParams.ts index 470bd6025a7..48a18febd68 100644 --- a/packages/ra-core/src/controller/useListParams.ts +++ b/packages/ra-core/src/controller/useListParams.ts @@ -241,7 +241,7 @@ const useListParams = ({ const showFilter = useCallback((filterName: string, defaultValue: any) => { // we don't use lodash.set() for displayed filters - // to avoid problkems with compound filter names (e.g. 'author.name') + // to avoid problems with compound filter names (e.g. 'author.name') const displayedFilters = { ...displayedFilterValues, [filterName]: true,