Skip to content

Commit 4a3acde

Browse files
committed
Improve WithListContext query state components handling, handle offline and document it.
1 parent 7a4dcbd commit 4a3acde

File tree

2 files changed

+101
-58
lines changed

2 files changed

+101
-58
lines changed

docs/WithListContext.md

Lines changed: 68 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -104,36 +104,37 @@ import { WithListContext } from 'react-admin';
104104
import { Chip, Stack, Typography } from '@mui/material';
105105

106106
const TagList = ({data, isPending}) => (
107-
<WithListContext
108-
data={data}
109-
isPending={isPending}
107+
<WithListContext
108+
data={data}
109+
isPending={isPending}
110110
loading={<Typography>Loading tags...</Typography>}
111-
empty={<Typography>No associated tags</Typography>}
112-
render={({ data }) => (
113-
<Stack direction="row" spacing={1}>
114-
{data.map(tag => (
115-
<Chip key={tag.id} label={tag.name} />
116-
))}
117-
</Stack>
118-
)}
119-
/>
111+
empty={<Typography>No associated tags</Typography>}
112+
render={({ data }) => (
113+
<Stack direction="row" spacing={1}>
114+
{data.map(tag => (
115+
<Chip key={tag.id} label={tag.name} />
116+
))}
117+
</Stack>
118+
)}
119+
/>
120120
);
121121
```
122122

123123
## Props
124124

125125
`<WithListContext>` accepts a single `render` prop, which should be a function.
126126

127-
| Prop | Required | Type | Default | Description |
128-
|----------------|----------|----------------|---------|-----------------------------------------------------------|
129-
| `data` | Optional | `RecordType[]` | | The list data in standalone usage. |
130-
| `empty` | Optional | `ReactNode` | | The component to display when the data is empty. |
131-
| `error` | Optional | `Error` | | The error in standalone usage. |
132-
| `errorElement` | Optional | `ReactNode` | | The component to display in case of error. |
133-
| `isPending` | Optional | `boolean` | | Determine if the list is loading in standalone usage. |
134-
| `loading` | Optional | `ReactNode` | | The component to display while checking authorizations. |
135-
| `render` | Required | `function` | | The function to render the data |
136-
| `total` | Optional | `number` | | The total number of data in the list in standalone usage. |
127+
| Prop | Required | Type | Default | Description |
128+
|----------------|----------|----------------|---------|-------------------------------------------------------------------------------------------|
129+
| `data` | Optional | `RecordType[]` | | The list data in standalone usage. |
130+
| `empty` | Optional | `ReactNode` | | The component to display when the data is empty. |
131+
| `error` | Optional | `Error` | | The error in standalone usage. |
132+
| `errorElement` | Optional | `ReactNode` | | The component to display in case of error. |
133+
| `isPending` | Optional | `boolean` | | Determine if the list is loading in standalone usage. |
134+
| `loading` | Optional | `ReactNode` | | The component to display while checking authorizations. |
135+
| `offline` | Optional | `ReactNode` | | The component to display when there is no connectivity to load data and no data in cache. |
136+
| `render` | Required | `function` | | The function to render the data |
137+
| `total` | Optional | `number` | | The total number of data in the list in standalone usage. |
137138

138139
## `empty`
139140

@@ -143,18 +144,18 @@ If `empty` is not provided, the render function will be called with empty data.
143144

144145
```jsx
145146
<WithListContext
146-
empty={<p>no books</p>}
147-
render={({ data }) => (
148-
<ul>
149-
{data.map(book => (
150-
<li key={book.id}>
151-
<i>{book.title}</i>, published on
152-
{book.published_at}
153-
</li>
154-
))}
155-
</ul>
156-
)}
157-
loading={<p>Loading...</p>}
147+
empty={<p>no books</p>}
148+
render={({ data }) => (
149+
<ul>
150+
{data.map(book => (
151+
<li key={book.id}>
152+
<i>{book.title}</i>, published on
153+
{book.published_at}
154+
</li>
155+
))}
156+
</ul>
157+
)}
158+
loading={<p>Loading...</p>}
158159
/>
159160
```
160161

@@ -189,17 +190,39 @@ If `loading` is not provided, the render function will be called with `isPending
189190

190191
```jsx
191192
<WithListContext
192-
loading={<p>loading...</p>}
193-
render={({ data }) => (
194-
<ul>
195-
{data.map(book => (
196-
<li key={book.id}>
197-
<i>{book.title}</i>, published on
198-
{book.published_at}
199-
</li>
200-
))}
201-
</ul>
202-
)}
193+
loading={<p>loading...</p>}
194+
render={({ data }) => (
195+
<ul>
196+
{data.map(book => (
197+
<li key={book.id}>
198+
<i>{book.title}</i>, published on
199+
{book.published_at}
200+
</li>
201+
))}
202+
</ul>
203+
)}
204+
/>
205+
```
206+
207+
## `offline`
208+
209+
Use `offline` to display a component when there is no connectivity to load data and no data in cache.
210+
211+
If `offline` is not provided, the render function will be called with `isPaused` as true and no data.
212+
213+
```jsx
214+
<WithListContext
215+
offline={<p>Offline</p>}
216+
render={({ data }) => (
217+
<ul>
218+
{data.map(book => (
219+
<li key={book.id}>
220+
<i>{book.title}</i>, published on
221+
{book.published_at}
222+
</li>
223+
))}
224+
</ul>
225+
)}
203226
/>
204227
```
205228

packages/ra-core/src/controller/list/WithListContext.tsx

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,38 +22,58 @@ import { useListContextWithProps } from './useListContextWithProps';
2222
export const WithListContext = <RecordType extends RaRecord>({
2323
empty,
2424
loading,
25+
offline,
2526
errorElement,
2627
render,
28+
children,
2729
...props
2830
}: WithListContextProps<RecordType>) => {
2931
const context = useListContextWithProps<RecordType>(props);
30-
const { data, total, isPending, error } = context;
32+
const { data, total, isPaused, isPending, isPlaceholderData, error } =
33+
context;
3134

32-
if (isPending === true && loading) {
35+
if (!isPaused && isPending && loading !== false && loading !== undefined) {
3336
return loading;
3437
}
3538

36-
if (error && errorElement) {
39+
if (
40+
isPaused &&
41+
(isPending || isPlaceholderData) &&
42+
offline !== false &&
43+
offline !== undefined
44+
) {
45+
return offline;
46+
}
47+
48+
if (error && errorElement !== false && errorElement !== undefined) {
3749
return errorElement;
3850
}
3951

40-
if ((data == null || data.length === 0 || total === 0) && empty) {
52+
if (
53+
(data == null || data.length === 0 || total === 0) &&
54+
empty !== false &&
55+
empty !== undefined
56+
) {
4157
return empty;
4258
}
4359

44-
return render(context) || null;
60+
return render(context) || children;
4561
};
4662

47-
export type WithListContextProps<RecordType extends RaRecord> = Partial<
48-
Pick<
49-
ListControllerResult<RecordType>,
50-
'data' | 'total' | 'isPending' | 'error'
51-
>
52-
> & {
63+
export interface WithListContextProps<RecordType extends RaRecord>
64+
extends React.PropsWithChildren<
65+
Partial<
66+
Pick<
67+
ListControllerResult<RecordType>,
68+
'data' | 'total' | 'isPending' | 'error'
69+
>
70+
>
71+
> {
5372
render: (
5473
context: Partial<ListControllerResult<RecordType>>
5574
) => ReactElement | false | null;
56-
empty?: React.ReactNode;
5775
loading?: React.ReactNode;
76+
offline?: React.ReactNode;
5877
errorElement?: React.ReactNode;
59-
};
78+
empty?: React.ReactNode;
79+
}

0 commit comments

Comments
 (0)