Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add queryOptions support for ReferenceManyField #9750

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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