Skip to content

Commit ab82156

Browse files
committed
Add optional loading, error and empty props to ReferenceBase commponents
1 parent 8046b0e commit ab82156

File tree

4 files changed

+75
-14
lines changed

4 files changed

+75
-14
lines changed

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ export const ReferenceArrayFieldBase = <
7474
const {
7575
children,
7676
render,
77+
error,
78+
loading,
79+
empty,
7780
filter,
7881
page = 1,
7982
perPage,
@@ -105,6 +108,34 @@ export const ReferenceArrayFieldBase = <
105108
);
106109
}
107110

111+
if (controllerProps.isPending && loading) {
112+
return loading;
113+
}
114+
if (controllerProps.error && error) {
115+
return error;
116+
}
117+
if (
118+
// there is an empty page component
119+
empty &&
120+
// there is no error
121+
!controllerProps.error &&
122+
// the list is not loading data for the first time
123+
!controllerProps.isPending &&
124+
// the API returned no data (using either normal or partial pagination)
125+
(controllerProps.total === 0 ||
126+
(controllerProps.total == null &&
127+
// @ts-ignore FIXME total may be undefined when using partial pagination but the ListControllerResult type is wrong about it
128+
controllerProps.hasPreviousPage === false &&
129+
// @ts-ignore FIXME total may be undefined when using partial pagination but the ListControllerResult type is wrong about it
130+
controllerProps.hasNextPage === false &&
131+
// @ts-ignore FIXME total may be undefined when using partial pagination but the ListControllerResult type is wrong about it
132+
controllerProps.data.length === 0)) &&
133+
// the user didn't set any filters
134+
!Object.keys(controllerProps.filterValues).length
135+
) {
136+
return empty;
137+
}
138+
108139
return (
109140
<ResourceContextProvider value={reference}>
110141
<ListContextProvider value={controllerProps}>
@@ -120,6 +151,9 @@ export interface ReferenceArrayFieldBaseProps<
120151
> extends BaseFieldProps<RecordType> {
121152
children?: ReactNode;
122153
render?: (props: ListControllerResult<ReferenceRecordType>) => ReactElement;
154+
error?: ReactNode;
155+
loading?: ReactNode;
156+
empty?: ReactNode;
123157
filter?: FilterPayload;
124158
page?: number;
125159
perPage?: number;

packages/ra-core/src/controller/field/ReferenceFieldBase.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export const ReferenceFieldBase = <
4747
>(
4848
props: ReferenceFieldBaseProps<ReferenceRecordType>
4949
) => {
50-
const { children, render, empty = null } = props;
50+
const { children, render, loading, error, empty = null } = props;
5151
const id = useFieldValue(props);
5252

5353
const controllerProps =
@@ -59,6 +59,12 @@ export const ReferenceFieldBase = <
5959
);
6060
}
6161

62+
if (controllerProps.isPending && loading) {
63+
return loading;
64+
}
65+
if (controllerProps.error && error) {
66+
return error;
67+
}
6268
if (
6369
(empty &&
6470
// no foreign key value
@@ -92,6 +98,7 @@ export interface ReferenceFieldBaseProps<
9298
className?: string;
9399
empty?: ReactNode;
94100
error?: ReactNode;
101+
loading?: ReactNode;
95102
queryOptions?: Partial<
96103
UseQueryOptions<ReferenceRecordType[], Error> & {
97104
meta?: any;

packages/ra-core/src/controller/field/ReferenceManyFieldBase.tsx

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ export const ReferenceManyFieldBase = <
6565
render,
6666
debounce,
6767
empty,
68+
error,
69+
loading,
6870
filter = defaultFilter,
6971
page = 1,
7072
perPage = 25,
@@ -96,6 +98,18 @@ export const ReferenceManyFieldBase = <
9698
queryOptions,
9799
});
98100

101+
if (!render && !children) {
102+
throw new Error(
103+
"<ReferenceManyFieldBase> requires either a 'render' prop or 'children' prop"
104+
);
105+
}
106+
107+
if (controllerProps.isPending && loading) {
108+
return loading;
109+
}
110+
if (controllerProps.error && error) {
111+
return error;
112+
}
99113
if (
100114
// there is an empty page component
101115
empty &&
@@ -118,12 +132,6 @@ export const ReferenceManyFieldBase = <
118132
return empty;
119133
}
120134

121-
if (!render && !children) {
122-
throw new Error(
123-
"<ReferenceManyFieldBase> requires either a 'render' prop or 'children' prop"
124-
);
125-
}
126-
127135
return (
128136
<ResourceContextProvider value={reference}>
129137
<ListContextProvider value={controllerProps}>
@@ -143,6 +151,8 @@ export interface ReferenceManyFieldBaseProps<
143151
children?: ReactNode;
144152
render?: (props: ListControllerResult<ReferenceRecordType>) => ReactNode;
145153
empty?: ReactNode;
154+
error?: ReactNode;
155+
loading?: ReactNode;
146156
}
147157

148158
const defaultFilter = {};

packages/ra-core/src/controller/field/ReferenceOneFieldBase.tsx

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ export const ReferenceOneFieldBase = <
3636
source = 'id',
3737
target,
3838
empty,
39+
error,
40+
loading,
3941
sort,
4042
filter,
4143
link,
@@ -69,20 +71,26 @@ export const ReferenceOneFieldBase = <
6971
[controllerProps, path]
7072
);
7173

74+
if (!render && !children) {
75+
throw new Error(
76+
"<ReferenceOneFieldBase> requires either a 'render' prop or 'children' prop"
77+
);
78+
}
79+
7280
const recordFromContext = useRecordContext<RecordType>(props);
81+
if (controllerProps.isPending && loading) {
82+
return loading;
83+
}
84+
if (controllerProps.error && error) {
85+
return error;
86+
}
7387
if (
7488
!recordFromContext ||
7589
(!controllerProps.isPending && controllerProps.referenceRecord == null)
7690
) {
7791
return empty;
7892
}
7993

80-
if (!render && !children) {
81-
throw new Error(
82-
"<ReferenceOneFieldBase> requires either a 'render' prop or 'children' prop"
83-
);
84-
}
85-
8694
return (
8795
<ResourceContextProvider value={reference}>
8896
<ReferenceFieldContextProvider value={context}>
@@ -102,8 +110,10 @@ export interface ReferenceOneFieldBaseProps<
102110
ReferenceRecordType
103111
> {
104112
children?: ReactNode;
113+
loading?: ReactNode;
114+
error?: ReactNode;
115+
empty?: ReactNode;
105116
render?: (props: UseReferenceResult<ReferenceRecordType>) => ReactNode;
106117
link?: LinkToType<ReferenceRecordType>;
107-
empty?: ReactNode;
108118
resource?: string;
109119
}

0 commit comments

Comments
 (0)