Skip to content

Commit 979444c

Browse files
committed
Fix base stories and doc
1 parent a701965 commit 979444c

File tree

6 files changed

+118
-149
lines changed

6 files changed

+118
-149
lines changed

docs/ReferenceArrayFieldBase.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ storybook_path: ra-core-fields-referencearrayfieldbase--basic
99
Use `<ReferenceArrayFieldBase>` to display a list of related records, via a one-to-many relationship materialized by an array of foreign keys.
1010

1111
`<ReferenceArrayFieldBase>` fetches a list of referenced records (using the `dataProvider.getMany()` method), and puts them in a [`ListContext`](./useListContext.md). This component is headless, and its children need to use the data from this context to render the desired ui.
12-
For a component handling the UI too use [the `<ReferenceArrayField>` component](./ReferenceArrayField.md) instead.
12+
13+
**Tip**: For a rendering a list of chips by default, use [the `<ReferenceArrayField>` component](./ReferenceArrayField.md) instead.
1314

1415
**Tip**: If the relationship is materialized by a foreign key on the referenced resource, use [the `<ReferenceManyFieldBase>` component](./ReferenceManyFieldBase.md) instead.
1516

@@ -100,11 +101,9 @@ You can change how the list of related records is rendered by passing a custom c
100101
101102
## `children`
102103
103-
You can pass any component of your own as child, to render the list of related records as you wish.
104-
You can access the list context using the `useListContext` hook.
104+
You can pass any React component as child, to render the list of related records based on the `ListContext`.
105105
106106
```jsx
107-
108107
<ReferenceArrayFieldBase label="Tags" reference="tags" source="tag_ids">
109108
<TagList />
110109
</ReferenceArrayFieldBase>
@@ -131,8 +130,7 @@ const TagList = (props: { children: React.ReactNode }) => {
131130
132131
## `render`
133132
134-
Alternatively to children you can pass a `render` function prop to `<ReferenceArrayFieldBase>`. The `render` prop will receive the `ListContext` as its argument, allowing to inline the `render` logic.
135-
When receiving a `render` prop the `<ReferenceArrayFieldBase>` component will ignore the children property.
133+
Alternatively to `children`, you can pass a `render` function prop to `<ReferenceArrayFieldBase>`. The `render` prop will receive the `ListContext` as its argument, allowing to inline the rendering logic.
136134
137135
```jsx
138136
<ReferenceArrayFieldBase
@@ -157,6 +155,8 @@ When receiving a `render` prop the `<ReferenceArrayFieldBase>` component will ig
157155
/>
158156
```
159157
158+
**Tip**: When receiving a `render` prop, the `<ReferenceArrayFieldBase>` component will ignore the `children` property.
159+
160160
## `filter`
161161
162162
`<ReferenceArrayFieldBase>` fetches all the related records, and displays them all, too. You can use the `filter` prop to filter the list of related records to display (this works by filtering the records client-side, after the fetch).

docs/ReferenceManyFieldBase.md

Lines changed: 28 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
---
22
layout: default
33
title: "The ReferenceManyFieldBase Component"
4-
storybook_path: ra-ui-materialui-fields-referencemanyfieldbase--basic
4+
storybook_path: ra-core-controller-field-referencemanyfieldbase--basic
55
---
66

77
# `<ReferenceManyFieldBase>`
88

99
`<ReferenceManyFieldBase>` is useful for displaying a list of related records via a one-to-many relationship, when the foreign key is carried by the referenced resource.
1010

11-
This component fetches a list of referenced records by a reverse lookup of the current `record.id` in the `target` field of another resource (using the `dataProvider.getManyReference()` REST method), and puts them in a [`ListContext`](./useListContext.md). This component is headless, and its children need to use the data from this context to render the desired ui.
12-
For a component handling the UI too use [the `<ReferenceManyField>` component](./ReferenceManyField.md) instead.
11+
This component fetches a list of referenced records by a reverse lookup of the current `record.id` in the `target` field of another resource (using the `dataProvider.getManyReference()` REST method), and puts them in a [`ListContext`](./useListContext.md).
12+
13+
This component is headless. It relies on its `children` or a `render` prop to render the desired ui.
1314

1415
**Tip**: If the relationship is materialized by an array of ids in the initial record, use [the `<ReferenceArrayFieldBase>` component](./ReferenceArrayFieldBase.md) instead.
1516

1617
## Usage
1718

18-
### With children
19-
2019
For instance, if an `author` has many `books`, and each book resource exposes an `author_id` field:
2120

2221
```
@@ -35,6 +34,14 @@ For instance, if an `author` has many `books`, and each book resource exposes an
3534
```jsx
3635
import { ShowBase, ReferenceManyFieldBase } from 'react-admin';
3736

37+
const AuthorShow = () => (
38+
<ShowBase>
39+
<ReferenceManyFieldBase reference="books" target="author_id" >
40+
<BookList source="title" />
41+
</ReferenceManyFieldBase>
42+
</ShowBase>
43+
);
44+
3845
const BookList = ({
3946
source,
4047
children,
@@ -58,14 +65,6 @@ const BookList = ({
5865
</p>
5966
);
6067
};
61-
62-
const AuthorShow = () => (
63-
<ShowBase>
64-
<ReferenceManyFieldBase reference="books" target="author_id" >
65-
<BookList source="title" />
66-
</ReferenceManyFieldBase>
67-
</ShowBase>
68-
);
6968
```
7069
7170
`<ReferenceManyFieldBase>` accepts a `reference` attribute, which specifies the resource to fetch for the related record. It also accepts a `source` attribute which defines the field containing the value to look for in the `target` field of the referenced resource. By default, this is the `id` of the resource (`authors.id` in the previous example).
@@ -91,7 +90,7 @@ export const PostList = () => (
9190
| Prop | Required | Type | Default | Description |
9291
| -------------- | -------- | --------------------------------------------------------------------------------- | -------------------------------- | ----------------------------------------------------------------------------------- |
9392
| `children` | Optional | `Element` | - | One or several elements that render a list of records based on a `ListContext` |
94-
| `render` | Optional\* | `(ListContext) => Element` | - | Function that receives a `ListContext` and render elements |
93+
| `render` | Optional\* | `(ListContext) => Element` | - | Function that receives a `ListContext` and returns an element |
9594
| `debounce` | Optional\* | `number` | 500 | debounce time in ms for the `setFilters` callbacks |
9695
| `empty` | Optional | `ReactNode` | - | Element to display when there are no related records. |
9796
| `filter` | Optional | `Object` | - | Filters to use when fetching the related records, passed to `getManyReference()` |
@@ -116,20 +115,21 @@ export const PostList = () => (
116115
- [`<EditableDatagrid>`](./EditableDatagrid.md)
117116
- [`<Calendar>`](./Calendar.md)
118117
119-
For instance, use a `<DataTable>` to render the related records in a table:
118+
For instance, use a `<ListIterator>` to render the related records:
120119
121120
```jsx
122121
import { ShowBase, ReferenceManyFieldBase, ListIterator } from 'react-admin';
123122

124123
export const AuthorShow = () => (
125124
<ShowBase>
126125
<ReferenceManyFieldBase label="Books" reference="books" target="author_id">
127-
<ListIterator render={(book) => (
128-
<div>
129-
<p>{book.title}</p>
130-
<p>{book.published_at}</p>
131-
</div>
132-
)}/>
126+
<ul>
127+
<ListIterator render={(book) => (
128+
<li key={book.id}>
129+
<i>{book.title}</i>, published on{' '}{book.published_at}
130+
</li>
131+
)}/>
132+
</ul>
133133
</ReferenceManyFieldBase>
134134
</ShowBase>
135135
);
@@ -159,14 +159,13 @@ const AuthorShow = () => (
159159
return <p className="error">{error.toString()}</p>;
160160
}
161161
return (
162-
<p>
162+
<ul>
163163
{data.map((book, index) => (
164-
<div key={index}>
165-
<p>{book.title}</p>
166-
<p>{book.published_at}</p>
167-
</div>
164+
<li key={index}>
165+
<i>{book.title}</i>, published on{' '}{book.published_at}
166+
</li>
168167
))}
169-
</p>
168+
</ul>
170169
);
171170
}
172171
}
@@ -278,12 +277,7 @@ For instance, if you want to display the `books` of a given `author`, the `refer
278277
279278
```jsx
280279
<ReferenceManyFieldBase label="Books" reference="books" target="author_id">
281-
<ListIterator render={(book) => (
282-
<div>
283-
<p>{book.title}</p>
284-
<p>{book.published_at}</p>
285-
</div>
286-
)} />
280+
...
287281
</ReferenceManyFieldBase>
288282
```
289283
@@ -361,13 +355,6 @@ Name of the field carrying the relationship on the referenced resource. For inst
361355
362356
```jsx
363357
<ReferenceManyFieldBase label="Books" reference="books" target="author_id">
364-
<ListIterator
365-
render={(book) => (
366-
<div>
367-
<p>{book.title}</p>
368-
<p>{book.published_at}</p>
369-
</div>
370-
)}
371-
/>
358+
...
372359
</ReferenceManyFieldBase>
373360
```

docs/ReferenceOneFieldBase.md

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,17 @@ This field fetches a one-to-one relationship, e.g. the details of a book, when u
2121

2222
`<ReferenceOneFieldBase>` behaves like `<ReferenceManyFieldBase>`: it uses the current `record` (a book in this example) to build a filter for the book details with the foreign key (`book_id`). Then, it uses `dataProvider.getManyReference('book_details', { target: 'book_id', id: book.id })` to fetch the related details, and takes the first one.
2323

24-
`<ReferenceOneFieldBase>` is a headless component, handling only the logic. This allows to use any UI library for the render. For a version based on MUI see [`<ReferenceOneField>`](/ReferenceOneField.html)
24+
`<ReferenceOneFieldBase>` is a headless component, handling only the logic and relying on its `children` or `render` prop to render the UI.
2525

26-
For the inverse relationships (the book linked to a book_detail), you can use a [`<ReferenceFieldBase>`](./ReferenceFieldBase.md).
26+
**Tip**: For a version based on MUI, see [`<ReferenceOneField>`](/ReferenceOneField.html)
27+
28+
**Tip**: For the inverse relationships (the book linked to a book_detail), you can use a [`<ReferenceFieldBase>`](./ReferenceFieldBase.md).
2729

2830
## Usage
2931

3032
Here is how to render a field of the `book_details` resource inside a Show view for the `books` resource:
3133

3234
```jsx
33-
3435
const BookShow = () => (
3536
<ShowBase>
3637
<ReferenceOneFieldBase reference="book_details" target="book_id">
@@ -39,8 +40,7 @@ const BookShow = () => (
3940
</ShowBase>
4041
);
4142

42-
// with BookDetails something like
43-
const BookDetails = ({ source }) => {
43+
const BookDetails = () => {
4444
const context = useReferenceFieldContext({
4545
reference,
4646
target,
@@ -53,10 +53,13 @@ const BookDetails = ({ source }) => {
5353
if (context.error) {
5454
return <p className="error" >{context.error.toString()}</p>;
5555
}
56+
if (!context.referenceRecord) {
57+
return <p>No details found</p>;
58+
}
5659
return (
5760
<div>
58-
<p>{record ? record.genre : ''}</p>
59-
<p>{record ? record.ISBN : ''}</p>
61+
<p>{context.referenceRecord.genre}</p>
62+
<p>{context.referenceRecord.ISBN}</p>
6063
</div>
6164
);
6265
}
@@ -88,6 +91,12 @@ You can pass any component of your own as children, to render the referenced rec
8891
You can access the list context using the `useReferenceFieldContext` hook.
8992

9093
```jsx
94+
const BookShow = () => (
95+
<ReferenceOneFieldBase reference="book_details" target="book_id">
96+
<BookDetails />
97+
</ReferenceOneFieldBase>
98+
);
99+
91100
const BookDetails = () => {
92101
const { isPending, error, referenceRecord } = useReferenceFieldContext({
93102
reference,
@@ -101,19 +110,16 @@ const BookDetails = () => {
101110
if (error) {
102111
return <p className="error" >{error.toString()}</p>;
103112
}
113+
if (!referenceRecord) {
114+
return <p>No details found</p>;
115+
}
104116
return (
105117
<div>
106-
<p>{referenceRecord ? referenceRecord.genre : ''}</p>
107-
<p>{referenceRecord ? referenceRecord.ISBN : ''}</p>
118+
<p>{referenceRecord.genre}</p>
119+
<p>{referenceRecord.ISBN}</p>
108120
</div>
109121
);
110122
}
111-
112-
const BookShow = () => (
113-
<ReferenceOneFieldBase reference="book_details" target="book_id">
114-
<BookDetails />
115-
</ReferenceOneFieldBase>
116-
);
117123
```
118124

119125
## `render`
@@ -134,10 +140,14 @@ const BookShow = () => (
134140
if (error) {
135141
return <p className="error" >{error.toString()}</p>;
136142
}
143+
144+
if (!referenceRecord) {
145+
return <p>No details found</p>;
146+
}
137147
return (
138148
<div>
139-
<p>{referenceRecord ? referenceRecord.genre : ''}</p>
140-
<p>{referenceRecord ? referenceRecord.ISBN : ''}</p>
149+
<p>{referenceRecord.genre}</p>
150+
<p>{referenceRecord.ISBN}</p>
141151
</div>
142152
);
143153
}}
@@ -196,7 +206,7 @@ For instance, if a product has prices in many currencies, and you only want to r
196206

197207
## `link`
198208

199-
By default, `<ReferenceOneFieldBase>` will set pass a links to the edition page of the related record in the context.link. You can disable this behavior by setting the `link` prop to `false`.
209+
By default, `<ReferenceOneFieldBase>` populates the context with a `link` value that links to the edition page of the related record. You can disable this behavior by setting the `link` prop to `false`.
200210

201211
```jsx
202212
<ReferenceOneFieldBase label="Genre" reference="book_details" target="book_id" link={false}>

packages/ra-core/src/controller/field/ReferenceArrayFieldBase.stories.tsx

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,7 @@ export const Basic = ({
5656
source="members"
5757
reference="artists"
5858
>
59-
<MyReferenceArrayField>
60-
<List source="name" />
61-
</MyReferenceArrayField>
59+
<ArtistList />
6260
</ReferenceArrayFieldBase>
6361
</ShowBase>
6462
}
@@ -67,6 +65,25 @@ export const Basic = ({
6765
</TestMemoryRouter>
6866
);
6967

68+
const ArtistList = () => {
69+
const { isPending, error, data } = useListContext();
70+
71+
if (isPending) {
72+
return <p>Loading...</p>;
73+
}
74+
75+
if (error) {
76+
return <p style={{ color: 'red' }}>{error.toString()}</p>;
77+
}
78+
return (
79+
<p>
80+
{data.map((datum, index) => (
81+
<li key={index}>{datum.name}</li>
82+
))}
83+
</p>
84+
);
85+
};
86+
7087
const erroredDataProvider = {
7188
...defaultDataProvider,
7289
getMany: _resource => Promise.reject(new Error('Error')),
@@ -137,27 +154,3 @@ export const WithRenderProp = ({
137154
</CoreAdmin>
138155
</TestMemoryRouter>
139156
);
140-
141-
const MyReferenceArrayField = (props: { children: React.ReactNode }) => {
142-
const context = useListContext();
143-
144-
if (context.isPending) {
145-
return <p>Loading...</p>;
146-
}
147-
148-
if (context.error) {
149-
return <p style={{ color: 'red' }}>{context.error.toString()}</p>;
150-
}
151-
return props.children;
152-
};
153-
154-
const List = ({ source }: { source: string }) => {
155-
const listContext = useListContext();
156-
return (
157-
<p>
158-
{listContext.data?.map((datum, index) => (
159-
<li key={index}>{datum[source]}</li>
160-
))}
161-
</p>
162-
);
163-
};

0 commit comments

Comments
 (0)