From 6110ec36049640bc62b15de72810cb6391f1e155 Mon Sep 17 00:00:00 2001
From: Gildas Garcia <1122076+djhi@users.noreply.github.com>
Date: Mon, 26 Jun 2023 11:37:51 +0200
Subject: [PATCH 1/4] Memoize AutocompleteInput function props where possible
---
packages/ra-ui-materialui/src/input/AutocompleteInput.tsx | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx b/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx
index 623315f9a7a..d8a2cc9b4d2 100644
--- a/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx
+++ b/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx
@@ -33,6 +33,7 @@ import {
useTranslate,
warning,
useGetRecordRepresentation,
+ useEvent,
} from 'ra-core';
import {
SupportCreateSuggestionOptions,
@@ -151,13 +152,13 @@ export const AutocompleteInput = <
matchSuggestion,
margin,
fieldState: fieldStateOverride,
- filterToQuery = DefaultFilterToQuery,
+ filterToQuery: filterToQueryProp = DefaultFilterToQuery,
formState: formStateOverride,
multiple = false,
noOptionsText,
onBlur,
onChange,
- onCreate,
+ onCreate: onCreateProp,
openText = 'ra.action.open',
optionText,
optionValue,
@@ -175,6 +176,9 @@ export const AutocompleteInput = <
...rest
} = props;
+ const filterToQuery = useEvent(filterToQueryProp);
+ const onCreate = useEvent(onCreateProp);
+
const {
allChoices,
isLoading,
From 3b3d65f2059aee636e91a78aab7b81b6be5ec5b3 Mon Sep 17 00:00:00 2001
From: Gildas Garcia <1122076+djhi@users.noreply.github.com>
Date: Mon, 26 Jun 2023 11:38:16 +0200
Subject: [PATCH 2/4] Update documentation about AutocompleteInput and
AutocompleteArrayInput
---
docs/AutocompleteArrayInput.md | 53 +++++++++++++++++++++++++++-------
docs/AutocompleteInput.md | 27 ++++++++++++++++-
2 files changed, 68 insertions(+), 12 deletions(-)
diff --git a/docs/AutocompleteArrayInput.md b/docs/AutocompleteArrayInput.md
index 54a05903a35..e29ebddbf70 100644
--- a/docs/AutocompleteArrayInput.md
+++ b/docs/AutocompleteArrayInput.md
@@ -337,25 +337,37 @@ const choices = [
{ id: 123, first_name: 'Leo', last_name: 'Tolstoi' },
{ id: 456, first_name: 'Jane', last_name: 'Austen' },
];
+
+// Note we declared the function outside the component to avoid rerenders
const optionRenderer = choice => `${choice.first_name} ${choice.last_name}`;
```
-`optionText` also accepts a React Element, that will be rendered inside a [``](./useRecordContext.md) using the related choice as the `record` prop. You can use Field components there.
+**Tip**: Make sure you provide a stable reference to the function passed as `optionText`. Either declare it outside the component render function or wrap it inside a [`useCallback`](https://react.dev/reference/react/useCallback).
+
+`optionText` also accepts a React Element, that will be rendered inside a [``](./useRecordContext.md) using the related choice as the `record` prop. You can use Field components there. However, using an element as `optionText` implies that you also set two more props, `inputText` and `matchSuggestion`. See [Using A Custom Element For Options](#using-a-custom-element-for-options) for more details.
+
+`optionText` is also useful when the choices are records [fetched from another resource](#fetching-choices), and `` is a child of a [``](./ReferenceArrayInput.md).
```jsx
-const choices = [
- { id: 123, first_name: 'Leo', last_name: 'Tolstoi' },
- { id: 456, first_name: 'Jane', last_name: 'Austen' },
-];
+import { AutocompleteArrayInput, ReferenceArrayInput } from 'react-admin';
-const FullNameField = () => {
- const record = useRecordContext();
- return {record.first_name} {record.last_name};
-}
+
+
+
+```
+
+In that case, react-admin uses the [`recordRepresentation`](./Resource.md#recordrepresentation) of the related resource to display the record label. In the example above, `` uses the resource representation of the `authors` resource, which is the `name` property.
+
+But if you set the `optionText` prop, react-admin uses it instead of relying on `recordRepresentation`.
+
+```jsx
+import { AutocompleteArrayInput, ReferenceArrayInput } from 'react-admin';
-}/>
+
+
+
```
## `optionValue`
@@ -517,6 +529,7 @@ const OptionRenderer = () => {
);
};
+const optionText = ;
const inputText = choice => `${choice.first_name} ${choice.last_name}`;
const matchSuggestion = (filter, choice) => {
return (
@@ -528,12 +541,30 @@ const matchSuggestion = (filter, choice) => {
}
+ optionText={optionText}
inputText={inputText}
matchSuggestion={matchSuggestion}
/>
```
+**Tip**: Make sure you pass stable references to the functions passed to the `inputText` and `matchSuggestion` by either declaring them outside the component render function or by wrapping them in a [`useCallback`](https://react.dev/reference/react/useCallback).
+
+**Tip**: Make sure you pass a stable reference to the element passed to the `optionText` prop by calling it outside the component render function like so:
+
+```jsx
+const OptionRenderer = () => {
+ const record = useRecordContext();
+ return (
+
+
+ {record.first_name} {record.last_name}
+
+ );
+};
+
+const optionText = ;
+```
+
## Creating New Choices
The `` can allow users to create a new choice if either the `create` or `onCreate` prop is provided.
diff --git a/docs/AutocompleteInput.md b/docs/AutocompleteInput.md
index d48ddc650ed..49cfd6bafa4 100644
--- a/docs/AutocompleteInput.md
+++ b/docs/AutocompleteInput.md
@@ -370,10 +370,15 @@ const choices = [
{ id: 123, first_name: 'Leo', last_name: 'Tolstoi' },
{ id: 456, first_name: 'Jane', last_name: 'Austen' },
];
+
+// Note we declared the function outside the component to avoid rerenders
const optionRenderer = choice => `${choice.first_name} ${choice.last_name}`;
+
```
+**Tip**: Make sure you provide a stable reference to the function passed as `optionText`. Either declare it outside the component render function or wrap it inside a [`useCallback`](https://react.dev/reference/react/useCallback).
+
`optionText` also accepts a React Element, that will be rendered inside a [``](./useRecordContext.md) using the related choice as the `record` prop. You can use Field components there. However, using an element as `optionText` implies that you also set two more props, `inputText` and `matchSuggestion`. See [Using A Custom Element For Options](#using-a-custom-element-for-options) for more details.
`optionText` is also useful when the choices are records [fetched from another resource](#fetching-choices), and `` is a child of a [``](./ReferenceInput.md).
@@ -637,6 +642,8 @@ const OptionRenderer = () => {
);
};
+
+const optionText = ;
const inputText = choice => `${choice.first_name} ${choice.last_name}`;
const matchSuggestion = (filter, choice) => {
return (
@@ -648,12 +655,30 @@ const matchSuggestion = (filter, choice) => {
}
+ optionText={optionText}
inputText={inputText}
matchSuggestion={matchSuggestion}
/>
```
+**Tip**: Make sure you pass stable references to the functions passed to the `inputText` and `matchSuggestion` by either declaring them outside the component render function or by wrapping them in a [`useCallback`](https://react.dev/reference/react/useCallback).
+
+**Tip**: Make sure you pass a stable reference to the element passed to the `optionText` prop by calling it outside the component render function like so:
+
+```jsx
+const OptionRenderer = () => {
+ const record = useRecordContext();
+ return (
+
+
+ {record.first_name} {record.last_name}
+
+ );
+};
+
+const optionText = ;
+```
+
## Creating New Choices
The `` can allow users to create a new choice if either the `create` or `onCreate` prop is provided.
From 437e5b40826bf47864a8df41ac8b25a1089dcbd7 Mon Sep 17 00:00:00 2001
From: Gildas Garcia <1122076+djhi@users.noreply.github.com>
Date: Mon, 26 Jun 2023 12:40:25 +0200
Subject: [PATCH 3/4] Fix onCreate cannot be memoized
---
packages/ra-ui-materialui/src/input/AutocompleteInput.tsx | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx b/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx
index d8a2cc9b4d2..7496f2d8522 100644
--- a/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx
+++ b/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx
@@ -158,7 +158,7 @@ export const AutocompleteInput = <
noOptionsText,
onBlur,
onChange,
- onCreate: onCreateProp,
+ onCreate,
openText = 'ra.action.open',
optionText,
optionValue,
@@ -177,7 +177,6 @@ export const AutocompleteInput = <
} = props;
const filterToQuery = useEvent(filterToQueryProp);
- const onCreate = useEvent(onCreateProp);
const {
allChoices,
From da6a09f7ccb3ac0d02ac4c60b93df9f7c11bb79c Mon Sep 17 00:00:00 2001
From: Gildas Garcia <1122076+djhi@users.noreply.github.com>
Date: Mon, 3 Jul 2023 14:46:58 +0200
Subject: [PATCH 4/4] Adapt AutocompleteInput documentation to
AutocompleteArrayInput
---
docs/AutocompleteArrayInput.md | 43 ++++++++++++++++++++++------------
1 file changed, 28 insertions(+), 15 deletions(-)
diff --git a/docs/AutocompleteArrayInput.md b/docs/AutocompleteArrayInput.md
index e29ebddbf70..459e2d0e19c 100644
--- a/docs/AutocompleteArrayInput.md
+++ b/docs/AutocompleteArrayInput.md
@@ -310,27 +310,40 @@ If a prompt is not enough, you can use [the `create` prop](#create) to render a
## `optionText`
-You can customize the properties to use for the option name (instead of the default `name`) thanks to the `optionText` prop:
+By default, `` uses the `name` property as the text content of each option.
```jsx
-const choices = [
- { id: 'admin', label: 'Admin' },
- { id: 'u001', label: 'Editor' },
- { id: 'u002', label: 'Moderator' },
- { id: 'u003', label: 'Reviewer' },
-];
-
+import { AutocompleteArrayInput } from 'react-admin';
+
+
+// renders the following list of choices
+// - Tech
+// - Lifestyle
+// - People
```
-`optionText` is especially useful when the choices are records coming from a `` or a ``. By default, react-admin uses the [`recordRepresentation`](./Resource.md#recordrepresentation) function to display the record label. But if you set the `optionText` prop, react-admin will use it instead.
+If your `choices` don't have a `name` property, or if you want to use another property, you can use the `optionText` prop to specify which property to use:
```jsx
-
-
-
+
```
-`optionText` also accepts a function, so you can shape the option text based on the entire choice object:
+`optionText` also accepts a function, so you can shape the option text at will:
```jsx
const choices = [
@@ -353,7 +366,7 @@ const optionRenderer = choice => `${choice.first_name} ${choice.last_name}`;
```jsx
import { AutocompleteArrayInput, ReferenceArrayInput } from 'react-admin';
-
+
```
@@ -365,7 +378,7 @@ But if you set the `optionText` prop, react-admin uses it instead of relying on
```jsx
import { AutocompleteArrayInput, ReferenceArrayInput } from 'react-admin';
-
+
```