Skip to content

Commit c886868

Browse files
committed
add render props to ShowBase component
1 parent 819261b commit c886868

File tree

5 files changed

+48
-5
lines changed

5 files changed

+48
-5
lines changed

docs/CreateBase.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const BookCreate = () => (
4646
You can customize the `<CreateBase>` component using the following props, documented in the `<Create>` component:
4747

4848
* `children`: the components that renders the form
49-
* `render`: alternative to children, a function that takes the EditController context and renders the form
49+
* `render`: alternative to children, a function that takes the CreateController context and renders the form
5050
* [`disableAuthentication`](./Create.md#disableauthentication): disable the authentication check
5151
* [`mutationMode`](./Create.md#mutationmode): Switch to optimistic or undoable mutations (pessimistic by default)
5252
* [`mutationOptions`](./Create.md#mutationoptions): options for the `dataProvider.create()` call

docs/ShowBase.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ const App = () => (
6262

6363
| Prop | Required | Type | Default | Description
6464
|------------------|----------|-------------------|---------|--------------------------------------------------------
65-
| `children` | Required | `ReactNode` | | The components rendering the record fields
65+
| `children` | Optional | `ReactNode` | | The components rendering the record fields
66+
| `children` | Optional | `(props: ShowControllerResult<RecordType>) => ReactNode` | | Alternative to children, a function that takes the ShowController context and renders the form
6667
| `disable Authentication` | Optional | `boolean` | | Set to `true` to disable the authentication check
6768
| `empty WhileLoading` | Optional | `boolean` | | Set to `true` to return `null` while the list is loading
6869
| `id` | Optional | `string` | | The record identifier. If not provided, it will be deduced from the URL

packages/ra-core/src/controller/show/ShowBase.spec.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
DefaultTitle,
99
NoAuthProvider,
1010
WithAuthProviderNoAccessControl,
11+
WithRenderProp,
1112
} from './ShowBase.stories';
1213

1314
describe('ShowBase', () => {
@@ -105,4 +106,16 @@ describe('ShowBase', () => {
105106
fireEvent.click(screen.getByText('FR'));
106107
await screen.findByText("Détails de l'article Hello (fr)");
107108
});
109+
110+
it('should support render prop', async () => {
111+
const dataProvider = testDataProvider({
112+
// @ts-ignore
113+
getOne: jest.fn(() =>
114+
Promise.resolve({ data: { id: 12, test: 'Hello' } })
115+
),
116+
});
117+
render(<WithRenderProp dataProvider={dataProvider} />);
118+
expect(dataProvider.getOne).toHaveBeenCalled();
119+
await screen.findByText('Hello');
120+
});
108121
});

packages/ra-core/src/controller/show/ShowBase.stories.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,23 @@ export const AccessControl = ({
145145
</CoreAdminContext>
146146
);
147147

148+
export const WithRenderProp = ({
149+
dataProvider = defaultDataProvider,
150+
...props
151+
}: {
152+
dataProvider?: DataProvider;
153+
} & Partial<ShowBaseProps>) => (
154+
<CoreAdminContext dataProvider={dataProvider}>
155+
<ShowBase
156+
{...defaultProps}
157+
{...props}
158+
render={({ record }) => {
159+
return <p>{record?.test}</p>;
160+
}}
161+
/>
162+
</CoreAdminContext>
163+
);
164+
148165
const defaultDataProvider = testDataProvider({
149166
getOne: () =>
150167
// @ts-ignore

packages/ra-core/src/controller/show/ShowBase.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import * as React from 'react';
22

33
import { RaRecord } from '../../types';
4-
import { useShowController, ShowControllerProps } from './useShowController';
4+
import {
5+
useShowController,
6+
ShowControllerProps,
7+
ShowControllerResult,
8+
} from './useShowController';
59
import { ShowContextProvider } from './ShowContextProvider';
610
import { OptionalResourceContextProvider } from '../../core';
711
import { useIsAuthPending } from '../../auth';
@@ -37,6 +41,7 @@ import { useIsAuthPending } from '../../auth';
3741
*/
3842
export const ShowBase = <RecordType extends RaRecord = any>({
3943
children,
44+
render,
4045
loading = null,
4146
...props
4247
}: ShowBaseProps<RecordType>) => {
@@ -51,18 +56,25 @@ export const ShowBase = <RecordType extends RaRecord = any>({
5156
return loading;
5257
}
5358

59+
if (!render && !children) {
60+
throw new Error(
61+
'<ShowBase> requires either a `render` prop or `children` prop'
62+
);
63+
}
64+
5465
return (
5566
// We pass props.resource here as we don't need to create a new ResourceContext if the props is not provided
5667
<OptionalResourceContextProvider value={props.resource}>
5768
<ShowContextProvider value={controllerProps}>
58-
{children}
69+
{render ? render(controllerProps) : children}
5970
</ShowContextProvider>
6071
</OptionalResourceContextProvider>
6172
);
6273
};
6374

6475
export interface ShowBaseProps<RecordType extends RaRecord = RaRecord>
6576
extends ShowControllerProps<RecordType> {
66-
children: React.ReactNode;
77+
children?: React.ReactNode;
78+
render?: (props: ShowControllerResult<RecordType>) => React.ReactNode;
6779
loading?: React.ReactNode;
6880
}

0 commit comments

Comments
 (0)