Skip to content

Commit

Permalink
Merge pull request #9750 from marmelab/fix-reference-many-field-not-s…
Browse files Browse the repository at this point in the history
…upport-query-options-next

Add `queryOptions` support for `<ReferenceManyField>`
  • Loading branch information
adguernier authored Apr 2, 2024
2 parents 513d80d + 59f10e1 commit c797c0d
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 15 deletions.
35 changes: 24 additions & 11 deletions docs/ReferenceManyField.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,17 +101,18 @@ This example leverages [`<SingleFieldList>`](./SingleFieldList.md) to display an

## Props

| Prop | Required | Type | Default | Description |
| ------------ | -------- | --------- | ------- | ----------------------------------------------------------------------------------- |
| `target` | Required | `string` | - | Target field carrying the relationship on the referenced resource, e.g. 'user_id' |
| `reference` | Required | `string` | - | The name of the resource for the referenced records, e.g. 'books' |
| `children` | Required | `Element` | - | One or several elements that render a list of records based on a `ListContext` |
| `source` | Optional | `string` | `id` | Target field carrying the relationship on the source record (usually 'id') |
| `filter` | Optional | `Object` | - | Filters to use when fetching the related records, passed to `getManyReference()` |
| `pagination` | Optional | `Element` | - | Pagination element to display pagination controls. empty by default (no pagination) |
| `perPage` | Optional | `number` | 25 | Maximum number of referenced records to fetch |
| `sort` | Optional | `{ field, order }` | `{ field: 'id', order: 'DESC' }` | Sort order to use when fetching the related records, passed to `getManyReference()` |
| `debounce` | Optional | `number` | 500 | debounce time in ms for the `setFilters` callbacks |
| Prop | Required | Type | Default | Description |
| -------------- | -------- | --------------------------------------------------------------------------------- | -------------------------------- | ----------------------------------------------------------------------------------- |
| `children` | Required | `Element` | - | One or several elements that render a list of records based on a `ListContext` |
| `debounce` | Optional | `number` | 500 | debounce time in ms for the `setFilters` callbacks |
| `filter` | Optional | `Object` | - | Filters to use when fetching the related records, passed to `getManyReference()` |
| `pagination` | Optional | `Element` | - | Pagination element to display pagination controls. empty by default (no pagination) |
| `perPage` | Optional | `number` | 25 | Maximum number of referenced records to fetch |
| `queryOptions` | Optional | [`UseQuery Options`](https://tanstack.com/query/v3/docs/react/reference/useQuery) | `{}` | `react-query` options for the `getMany` query |
| `reference` | Required | `string` | - | The name of the resource for the referenced records, e.g. 'books' |
| `sort` | Optional | `{ field, order }` | `{ field: 'id', order: 'DESC' }` | Sort order to use when fetching the related records, passed to `getManyReference()` |
| `source` | Optional | `string` | `id` | Target field carrying the relationship on the source record (usually 'id') |
| `target` | Required | `string` | - | Target field carrying the relationship on the referenced resource, e.g. 'user_id' |

`<ReferenceManyField>` also accepts the [common field props](./Fields.md#common-field-props), except `emptyText` (use the child `empty` prop instead).

Expand Down Expand Up @@ -262,6 +263,18 @@ By default, react-admin restricts the possible values to 25 and displays no pagi
</ReferenceManyField>
```

## `queryOptions`

Use the `queryOptions` prop to pass options to [the `dataProvider.getMany()` query](./useGetOne.md#aggregating-getone-calls) that fetches the referenced record.

For instance, to pass [a custom `meta`](./Actions.md#meta-parameter):

{% raw %}
```jsx
<ReferenceManyField queryOptions={{ meta: { foo: 'bar' } }} />
```
{% endraw %}

## `reference`

The name of the resource to fetch for the related records.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useCallback, useEffect, useRef } from 'react';
import { UseQueryOptions } from '@tanstack/react-query';
import get from 'lodash/get';
import isEqual from 'lodash/isEqual';
import lodashDebounce from 'lodash/debounce';
Expand All @@ -14,7 +15,8 @@ import useSortState from '../useSortState';
import { useResourceContext } from '../../core';

export interface UseReferenceManyFieldControllerParams<
RecordType extends RaRecord = RaRecord
RecordType extends RaRecord = RaRecord,
ReferenceRecordType extends RaRecord = RaRecord
> {
debounce?: number;
filter?: any;
Expand All @@ -26,6 +28,10 @@ export interface UseReferenceManyFieldControllerParams<
sort?: SortPayload;
source?: string;
target: string;
queryOptions?: UseQueryOptions<
{ data: ReferenceRecordType[]; total: number },
Error
>;
}

const defaultFilter = {};
Expand Down Expand Up @@ -53,14 +59,18 @@ const defaultFilter = {};
* @param {string} props.resource The current resource name
* @param {Object} props.sort the sort to apply to the referenced records
* @param {string} props.source The key of the linked resource identifier
* @param {UseQuery Options} props.queryOptions `react-query` options`
*
* @returns {ListControllerResult} The reference many props
*/
export const useReferenceManyFieldController = <
RecordType extends RaRecord = RaRecord,
ReferenceRecordType extends RaRecord = RaRecord
>(
props: UseReferenceManyFieldControllerParams<RecordType>
props: UseReferenceManyFieldControllerParams<
RecordType,
ReferenceRecordType
>
): ListControllerResult<ReferenceRecordType> => {
const {
debounce = 500,
Expand All @@ -72,9 +82,14 @@ export const useReferenceManyFieldController = <
page: initialPage,
perPage: initialPerPage,
sort: initialSort = { field: 'id', order: 'DESC' },
queryOptions = {} as UseQueryOptions<
{ data: ReferenceRecordType[]; total: number },
Error
>,
} = props;
const notify = useNotify();
const resource = useResourceContext(props);
const { meta, ...otherQueryOptions } = queryOptions;

// pagination logic
const { page, setPage, perPage, setPerPage } = usePaginationState({
Expand Down Expand Up @@ -179,6 +194,7 @@ export const useReferenceManyFieldController = <
pagination: { page, perPage },
sort,
filter: filterValues,
meta,
},
{
enabled: get(record, source) != null,
Expand All @@ -200,6 +216,7 @@ export const useReferenceManyFieldController = <
},
}
),
...otherQueryOptions,
}
);

Expand Down
16 changes: 16 additions & 0 deletions packages/ra-ui-materialui/src/field/ReferenceManyField.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,19 @@ export const WithFilter = () => (
</ReferenceManyField>
</Wrapper>
);

export const WithMeta = () => (
<Wrapper>
<ReferenceManyField
reference="books"
target="author_id"
queryOptions={{
meta: { foo: 'bar' },
}}
>
<Datagrid>
<TextField source="title" />
</Datagrid>
</ReferenceManyField>
</Wrapper>
);
12 changes: 10 additions & 2 deletions packages/ra-ui-materialui/src/field/ReferenceManyField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
useRecordContext,
RaRecord,
} from 'ra-core';
import { UseQueryOptions } from '@tanstack/react-query';

import { fieldPropTypes, FieldProps } from './types';

Expand Down Expand Up @@ -63,7 +64,7 @@ export const ReferenceManyField = <
RecordType extends RaRecord = RaRecord,
ReferenceRecordType extends RaRecord = RaRecord
>(
props: ReferenceManyFieldProps<RecordType>
props: ReferenceManyFieldProps<RecordType, ReferenceRecordType>
) => {
const {
children,
Expand All @@ -77,6 +78,7 @@ export const ReferenceManyField = <
sort = defaultSort,
source = 'id',
target,
queryOptions,
} = props;
const record = useRecordContext(props);

Expand All @@ -94,6 +96,7 @@ export const ReferenceManyField = <
sort,
source,
target,
queryOptions,
});

return (
Expand All @@ -107,7 +110,8 @@ export const ReferenceManyField = <
};

export interface ReferenceManyFieldProps<
RecordType extends Record<string, any> = Record<string, any>
RecordType extends Record<string, any> = Record<string, any>,
ReferenceRecordType extends Record<string, any> = Record<string, any>
> extends Omit<FieldProps<RecordType>, 'source'> {
children: ReactNode;
debounce?: number;
Expand All @@ -119,6 +123,10 @@ export interface ReferenceManyFieldProps<
sort?: SortPayload;
source?: string;
target: string;
queryOptions?: UseQueryOptions<
{ data: ReferenceRecordType[]; total: number },
Error
>;
}

ReferenceManyField.propTypes = {
Expand Down

0 comments on commit c797c0d

Please sign in to comment.