diff --git a/packages/ra-core/src/controller/field/ReferenceManyFieldController.spec.tsx b/packages/ra-core/src/controller/field/ReferenceManyFieldController.spec.tsx index e0d2af252a2..6f2175fab34 100644 --- a/packages/ra-core/src/controller/field/ReferenceManyFieldController.spec.tsx +++ b/packages/ra-core/src/controller/field/ReferenceManyFieldController.spec.tsx @@ -7,6 +7,138 @@ import renderWithRedux from '../../util/renderWithRedux'; describe('', () => { it('should set loaded to false when related records are not yet fetched', async () => { + const ComponentToTest = ({ loaded }: { loaded?: boolean }) => { + return
loaded: {loaded.toString()}
; + }; + + const { queryByText } = renderWithRedux( + + {props => } + , + { + admin: { + resources: { + bar: { + data: { + 1: { id: 1, title: 'hello' }, + 2: { id: 2, title: 'world' }, + }, + }, + }, + references: { + oneToMany: { + 'foo_bar@fooId_barId': {}, + }, + }, + }, + } + ); + + expect(queryByText('loaded: false')).not.toBeNull(); + await waitFor(() => { + expect(queryByText('loaded: true')).not.toBeNull(); + }); + }); + + it('should set loaded to true when related records have been fetched and there are no results', async () => { + const ComponentToTest = ({ loaded }: { loaded?: boolean }) => { + return
loaded: {loaded.toString()}
; + }; + + const { queryByText } = renderWithRedux( + + {props => } + , + { + admin: { + resources: { + bar: { + data: { + 1: { id: 1, title: 'hello' }, + 2: { id: 2, title: 'world' }, + }, + }, + }, + references: { + oneToMany: { + 'foo_bar@fooId_barId': { + ids: [], + }, + }, + }, + }, + } + ); + + expect(queryByText('loaded: false')).not.toBeNull(); + await waitFor(() => { + expect(queryByText('loaded: true')).not.toBeNull(); + }); + }); + + it('should set loaded to true when related records have been fetched and there are results', async () => { + const ComponentToTest = ({ loaded }: { loaded?: boolean }) => { + return
loaded: {loaded.toString()}
; + }; + + const { queryByText } = renderWithRedux( + + {props => } + , + { + admin: { + resources: { + bar: { + data: { + 1: { id: 1, title: 'hello' }, + 2: { id: 2, title: 'world' }, + }, + }, + }, + references: { + oneToMany: { + 'foo_bar@fooId_barId': { + ids: [1, 2], + }, + }, + }, + }, + } + ); + + expect(queryByText('loaded: false')).not.toBeNull(); + await waitFor(() => { + expect(queryByText('loaded: true')).not.toBeNull(); + }); + }); + + it('should call dataProvider.getManyReferences on mount', async () => { const children = jest.fn().mockReturnValue('children'); const { dispatch } = renderWithRedux( ', () => { reference="bar" target="foo_id" basePath="" + record={{ + id: 'fooId', + source: 'barId', + }} > {children} , diff --git a/packages/ra-core/src/dataProvider/useGetManyReference.ts b/packages/ra-core/src/dataProvider/useGetManyReference.ts index 2eb8c6bfa03..092bef6a493 100644 --- a/packages/ra-core/src/dataProvider/useGetManyReference.ts +++ b/packages/ra-core/src/dataProvider/useGetManyReference.ts @@ -7,6 +7,8 @@ import { SortPayload, Identifier, ReduxState, + Record, + RecordMap, } from '../types'; import useQueryWithStore from './useQueryWithStore'; import { @@ -93,19 +95,20 @@ const useGetManyReference = ( { ...options, relatedTo, action: CRUD_GET_MANY_REFERENCE }, // ids and data selector (state: ReduxState) => ({ - ids: getIds(state, relatedTo) || defaultIds, + ids: getIds(state, relatedTo), allRecords: get( state.admin.resources, [resource, 'data'], defaultData ), }), - (state: ReduxState) => getTotal(state, relatedTo) + (state: ReduxState) => getTotal(state, relatedTo), + isDataLoaded ); const data = useMemo( () => - ids === null + ids == null ? defaultData : ids .map(id => allRecords[id]) @@ -117,7 +120,14 @@ const useGetManyReference = ( [ids, allRecords] ); - return { data, ids, total, error, loading, loaded }; + return { data, ids: ids || defaultIds, total, error, loading, loaded }; }; +interface DataSelectorResult { + ids: Identifier[]; + allRecords: RecordMap; +} + +const isDataLoaded = (data: DataSelectorResult) => data.ids != null; + export default useGetManyReference;