Skip to content

Commit 5999871

Browse files
erwanMarmelabMadeorsk
authored andcommitted
Update WithListContext to accept optional empty, loading and error components
1 parent ac49416 commit 5999871

File tree

2 files changed

+156
-3
lines changed

2 files changed

+156
-3
lines changed

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

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,3 +222,134 @@ export const Chart = () => (
222222
</ListBase>
223223
</CoreAdminContext>
224224
);
225+
226+
const emptyDataProvider = fakerestDataProvider({ fruits: [] }, true);
227+
228+
export const Empty = () => (
229+
<CoreAdminContext dataProvider={emptyDataProvider}>
230+
<ListBase resource="fruits" disableSyncWithLocation perPage={100}>
231+
<WithListContext<Fruit>
232+
empty={<div>No fruits available</div>}
233+
render={({ isPending, data, total }) =>
234+
isPending ? (
235+
<>Loading...</>
236+
) : (
237+
<table style={{ borderSpacing: '30px 5px' }}>
238+
<thead>
239+
<tr>
240+
<th>Date</th>
241+
<th>Apples</th>
242+
<th>Blueberries</th>
243+
<th>Carrots</th>
244+
</tr>
245+
</thead>
246+
<tbody>
247+
{data.map(fruit => (
248+
<tr key={fruit.id}>
249+
<td>{fruit.date}</td>
250+
<td>{fruit.apples}</td>
251+
<td>{fruit.blueberries}</td>
252+
<td>{fruit.carrots}</td>
253+
</tr>
254+
))}
255+
</tbody>
256+
<tfoot>
257+
<tr>
258+
<td colSpan={4}>Total: {total}</td>
259+
</tr>
260+
</tfoot>
261+
</table>
262+
)
263+
}
264+
/>
265+
</ListBase>
266+
</CoreAdminContext>
267+
);
268+
269+
const foreverLoadingDataProvider = {
270+
...dataProvider,
271+
getList: _resource => new Promise(() => {}),
272+
} as any;
273+
274+
export const Loading = () => (
275+
<CoreAdminContext dataProvider={foreverLoadingDataProvider}>
276+
<ListBase resource="fruits" disableSyncWithLocation perPage={100}>
277+
<WithListContext<Fruit>
278+
loading={<>Loading...</>}
279+
render={({ data, total }) => (
280+
<table style={{ borderSpacing: '30px 5px' }}>
281+
<thead>
282+
<tr>
283+
<th>Date</th>
284+
<th>Apples</th>
285+
<th>Blueberries</th>
286+
<th>Carrots</th>
287+
</tr>
288+
</thead>
289+
<tbody>
290+
{data.map(fruit => (
291+
<tr key={fruit.id}>
292+
<td>{fruit.date}</td>
293+
<td>{fruit.apples}</td>
294+
<td>{fruit.blueberries}</td>
295+
<td>{fruit.carrots}</td>
296+
</tr>
297+
))}
298+
</tbody>
299+
<tfoot>
300+
<tr>
301+
<td colSpan={4}>Total: {total}</td>
302+
</tr>
303+
</tfoot>
304+
</table>
305+
)}
306+
/>
307+
</ListBase>
308+
</CoreAdminContext>
309+
);
310+
311+
const erroredDataProvider = {
312+
...dataProvider,
313+
getList: _resource => Promise.reject('Error'),
314+
} as any;
315+
316+
export const Error = () => (
317+
<CoreAdminContext dataProvider={erroredDataProvider}>
318+
<ListBase resource="fruits" disableSyncWithLocation perPage={100}>
319+
<WithListContext<Fruit>
320+
error={<p>Error</p>}
321+
render={({ isPending, data, total }) =>
322+
isPending ? (
323+
<>Loading...</>
324+
) : (
325+
<table style={{ borderSpacing: '30px 5px' }}>
326+
<thead>
327+
<tr>
328+
<th>Date</th>
329+
<th>Apples</th>
330+
<th>Blueberries</th>
331+
<th>Carrots</th>
332+
</tr>
333+
</thead>
334+
<tbody>
335+
{data.map(fruit => (
336+
<tr key={fruit.id}>
337+
<td>{fruit.date}</td>
338+
<td>{fruit.apples}</td>
339+
<td>{fruit.blueberries}</td>
340+
<td>{fruit.carrots}</td>
341+
</tr>
342+
))}
343+
</tbody>
344+
<tfoot>
345+
<tr>
346+
<td colSpan={4}>Total: {total}</td>
347+
</tr>
348+
</tfoot>
349+
</table>
350+
)
351+
}
352+
/>
353+
</ListBase>
354+
</CoreAdminContext>
355+
);

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

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ReactElement } from 'react';
1+
import React, { ReactElement } from 'react';
22
import { RaRecord } from '../../types';
33
import { ListControllerResult } from './useListController';
44
import { useListContext } from './useListContext';
@@ -20,15 +20,37 @@ import { useListContext } from './useListContext';
2020
* );
2121
*/
2222
export const WithListContext = <RecordType extends RaRecord>({
23+
empty,
24+
loading,
25+
error: errorElement,
2326
render,
24-
}: WithListContextProps<RecordType>) =>
25-
render(useListContext<RecordType>()) || null;
27+
}: WithListContextProps<RecordType>) => {
28+
const context = useListContext<RecordType>();
29+
const { data, total, isPending, error } = context;
30+
31+
if (isPending === true) {
32+
return loading ? loading : null;
33+
}
34+
35+
if (error) {
36+
return errorElement ? errorElement : null;
37+
}
38+
39+
if (data == null || data.length === 0 || total === 0) {
40+
return empty ? empty : null;
41+
}
42+
43+
return render(context) || null;
44+
};
2645

2746
export interface WithListContextProps<RecordType extends RaRecord> {
2847
render: (
2948
context: ListControllerResult<RecordType>
3049
) => ReactElement | false | null;
3150
label?: string;
51+
empty?: React.ReactElement;
52+
loading?: React.ReactElement;
53+
error?: React.ReactElement;
3254
}
3355

3456
/**

0 commit comments

Comments
 (0)