diff --git a/packages/ra-core/src/controller/field/ReferenceManyFieldController.tsx b/packages/ra-core/src/controller/field/ReferenceManyFieldController.tsx index f6b8adc9a3b..f627d7b962a 100644 --- a/packages/ra-core/src/controller/field/ReferenceManyFieldController.tsx +++ b/packages/ra-core/src/controller/field/ReferenceManyFieldController.tsx @@ -1,11 +1,9 @@ import { ReactElement, FunctionComponent } from 'react'; -import { - SORT_ASC, - SORT_DESC, -} from '../../reducer/admin/resource/list/queryReducer'; -import { Record, Sort, RecordMap, Identifier, Dispatch } from '../../types'; +import { Record, Sort, RecordMap, Identifier } from '../../types'; import useReferenceMany from './useReferenceMany'; +import useSort from '../useSort'; +import usePagination from '../usePagination'; interface ChildrenFuncParams { currentSort: Sort; @@ -35,17 +33,6 @@ interface Props { total?: number; } -const sortReducer = (state: Sort, field: string | Sort): Sort => { - if (typeof field !== 'string') { - return field; - } - const order = - state.field === field && state.order === SORT_ASC - ? SORT_DESC - : SORT_ASC; - return { field, order }; -}; - /** * Render related records to the current one. * @@ -100,21 +87,19 @@ export const ReferenceManyFieldController: FunctionComponent = ({ filter, source, basePath, - perPage, - sort, + perPage: initialPerPage, + sort: initialSort, children, }) => { + const { sort, sortBy } = useSort(initialSort); + const { page, perPage, setPage, setPerPage } = usePagination( + initialPerPage + ); const { - currentSort, data, ids, loadedOnce, - page, - currentPerPage, referenceBasePath, - setPage, - setPerPage, - setSort, total, } = useReferenceMany({ resource, @@ -125,20 +110,21 @@ export const ReferenceManyFieldController: FunctionComponent = ({ source, basePath, perPage, + page, sort, }); return children({ - currentSort, + currentSort: sort, data, ids, loadedOnce, page, - perPage: currentPerPage, + perPage, referenceBasePath, setPage, setPerPage, - setSort, + setSort: sortBy, total, }); }; diff --git a/packages/ra-core/src/controller/field/useReferenceMany.ts b/packages/ra-core/src/controller/field/useReferenceMany.ts index 87f50f5e3bd..7744e7bf046 100644 --- a/packages/ra-core/src/controller/field/useReferenceMany.ts +++ b/packages/ra-core/src/controller/field/useReferenceMany.ts @@ -1,13 +1,9 @@ -import { ReactNode, useState, useReducer, useEffect, useMemo } from 'react'; +import { useEffect, useMemo } from 'react'; // @ts-ignore import { useSelector, useDispatch } from 'react-redux'; import get from 'lodash/get'; import { crudGetManyReference } from '../../actions'; -import { - SORT_ASC, - SORT_DESC, -} from '../../reducer/admin/resource/list/queryReducer'; import { getIds, getReferences, @@ -17,16 +13,10 @@ import { import { Record, Sort, RecordMap, Identifier, Dispatch } from '../../types'; interface ChildrenFuncParams { - currentSort: Sort; data: RecordMap; ids: Identifier[]; loadedOnce: boolean; - page: number; - currentPerPage: number; referenceBasePath: string; - setPage: (page: number) => void; - setPerPage: (perPage: number) => void; - setSort: (field: string) => void; total: number; } @@ -36,7 +26,8 @@ interface Options { filter?: any; ids?: any[]; loadedOnce?: boolean; - perPage?: number; + page: number; + perPage: number; record?: Record; reference: string; resource: string; @@ -46,17 +37,6 @@ interface Options { total?: number; } -const sortReducer = (state: Sort, field: string | Sort): Sort => { - if (typeof field !== 'string') { - return field; - } - const order = - state.field === field && state.order === SORT_ASC - ? SORT_DESC - : SORT_ASC; - return { field, order }; -}; - const defaultFilter = {}; const useReferenceMany = ({ @@ -67,7 +47,8 @@ const useReferenceMany = ({ filter = defaultFilter, source, basePath, - perPage = 25, + page, + perPage, sort = { field: 'id', order: 'DESC' }, }: Options): ChildrenFuncParams => { const referenceId = get(record, source); @@ -81,11 +62,6 @@ const useReferenceMany = ({ relatedTo, ]); const total = useSelector(selectTotal(relatedTo), [relatedTo]); - const [page, setPage] = useState(1); - const [currentPerPage, setPerPage] = useState(perPage); - useEffect(() => setPerPage(perPage), [perPage]); - const [currentSort, setSort] = useReducer(sortReducer, sort); - useEffect(() => setSort(sort), [sort.field, sort.order]); const dispatch = useDispatch(); @@ -98,8 +74,8 @@ const useReferenceMany = ({ filter, source, page, - perPage: currentPerPage, - sort: currentSort, + perPage, + sort, dispatch, }), [ @@ -111,25 +87,19 @@ const useReferenceMany = ({ source, crudGetManyReference, page, - currentPerPage, - currentSort.field, - currentSort.order, + perPage, + sort.field, + sort.order, ] ); const referenceBasePath = basePath.replace(resource, reference); return { - currentSort, data, ids, loadedOnce: typeof ids !== 'undefined', - page, - currentPerPage, referenceBasePath, - setPage, - setPerPage, - setSort, total, }; }; diff --git a/packages/ra-core/src/controller/usePagination.ts b/packages/ra-core/src/controller/usePagination.ts new file mode 100644 index 00000000000..5808f152e8e --- /dev/null +++ b/packages/ra-core/src/controller/usePagination.ts @@ -0,0 +1,21 @@ +import { useState, useEffect } from 'react'; + +interface PaginationProps { + page: number; + perPage: number; + setPage: (page: number) => void; + setPerPage: (perPage: number) => void; +} + +export default (initialPerPage: number = 25): PaginationProps => { + const [page, setPage] = useState(1); + const [perPage, setPerPage] = useState(initialPerPage); + useEffect(() => setPerPage(initialPerPage), [initialPerPage]); + + return { + page, + perPage, + setPage, + setPerPage, + }; +}; diff --git a/packages/ra-core/src/controller/useSort.ts b/packages/ra-core/src/controller/useSort.ts new file mode 100644 index 00000000000..03acbc5499b --- /dev/null +++ b/packages/ra-core/src/controller/useSort.ts @@ -0,0 +1,31 @@ +import { useReducer, useEffect } from 'react'; + +import { + SORT_ASC, + SORT_DESC, +} from '../reducer/admin/resource/list/queryReducer'; +import { Sort } from '../types'; + +const sortReducer = (state: Sort, field: string | Sort): Sort => { + if (typeof field !== 'string') { + return field; + } + const order = + state.field === field && state.order === SORT_ASC + ? SORT_DESC + : SORT_ASC; + return { field, order }; +}; + +export default (initialSort: Sort = { field: 'id', order: 'DESC' }) => { + const [sort, dispatch] = useReducer(sortReducer, initialSort); + useEffect(() => dispatch(initialSort), [ + initialSort.field, + initialSort.order, + ]); + + return { + sortBy: (field: string) => dispatch(field), + sort, + }; +};