-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: support Component and Element for List props #10539
base: next
Are you sure you want to change the base?
Conversation
92437f9
to
abf98d3
Compare
@@ -139,6 +139,7 @@ export const PostList = () => ( | |||
</List> | |||
); | |||
``` | |||
You can use a `ReactElement` (e.g. `actions={<ListActions/>}`), a `ComponentType` (e.g. `actions={ListActions}`) or false to disable it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: I'd be tempted to use the component syntax in the example above (since it's shorter and offers better performances), and simply mention that action
also accepts the other types
You can use a `ReactElement` (e.g. `actions={<ListActions/>}`), a `ComponentType` (e.g. `actions={ListActions}`) or false to disable it. | |
**Tip:** `action` also accepts a `ReactElement` (e.g. `actions={<ListActions/>}`), or `false`. |
But on the other hand, it may be odd to encourage this syntax only for the List
component (since it's the only one we support for now...)
So I'm hesitating.
Same remark applies to other props below.
@fzaninotto @djhi wdyt?
@@ -175,7 +176,7 @@ The default `<List>` layout lets you render the component of your choice on the | |||
|
|||
 | |||
|
|||
Pass a React element as the `aside` prop for that purpose: | |||
Pass a React element or ComponentType as the `aside` prop for that purpose: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: I believe ComponentType
designates the type of such a component, but my understanding is that you can speak of a React Component (and a React Element)
Pass a React element or ComponentType as the `aside` prop for that purpose: | |
Pass a React element or component as the `aside` prop for that purpose: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But it IS expected a ComponentType (as defined in the ListViewProps
), otherwise we couldn't do aside={Aside}
. It let's the responsibility of the instanciation of the subcomponent (aside
) to the component (List
).
@@ -483,7 +484,7 @@ When there is no result, and there is no active filter, and the resource has a c | |||
|
|||
 | |||
|
|||
You can use the `empty` prop to replace that page by a custom component: | |||
You can use the `empty` prop to replace that page by a custom component, passing a ReactElement or ComponentType : |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use the `empty` prop to replace that page by a custom component, passing a ReactElement or ComponentType : | |
You can use the `empty` prop to replace that page by a custom React element or component: |
@@ -783,7 +784,7 @@ By default, the `<List>` view displays a set of pagination controls at the botto | |||
|
|||
 | |||
|
|||
The `pagination` prop allows to replace the default pagination controls by your own. | |||
The `pagination` prop allows to replace the default pagination controls by your own, either with a ReactElement or a ComponentType. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The `pagination` prop allows to replace the default pagination controls by your own, either with a ReactElement or a ComponentType. | |
The `pagination` prop allows to replace the default pagination controls by your own, either with a React element or component. |
@@ -990,7 +991,7 @@ export const PostList = () => ( | |||
); | |||
``` | |||
|
|||
The title can be a string, a React element, or `false` to disable the title. | |||
The title can be a string, a React element, a ComponentType or `false` to disable the title. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The title can be a string, a React element, a ComponentType or `false` to disable the title. | |
The title can be a string, a React element, a React component or `false` to disable the title. |
</ThemeProvider> | ||
</CoreAdminContext> | ||
); | ||
expect(screen.queryAllByText('Hello')).toHaveLength(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
expect(screen.queryAllByText('Hello')).toHaveLength(1); | |
screen.getByText('Hello'); |
await waitFor(() => { | ||
expect(screen.queryByText('resources.posts.empty')).toBeNull(); | ||
screen.getByText('Custom Empty'); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
await waitFor(() => { | |
expect(screen.queryByText('resources.posts.empty')).toBeNull(); | |
screen.getByText('Custom Empty'); | |
}); | |
await screen.findByText('Custom Empty'); | |
expect(screen.queryByText('resources.posts.empty')).toBeNull(); |
@@ -1,5 +1,5 @@ | |||
import * as React from 'react'; | |||
import { Admin, AutocompleteInput } from 'react-admin'; | |||
import { Admin, AutocompleteInput, Pagination } from 'react-admin'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
linter warning at this line
@@ -131,7 +167,7 @@ export interface ListViewProps { | |||
* </List> | |||
* ); | |||
*/ | |||
actions?: ReactElement | false; | |||
actions?: ReactElement | ComponentType | false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: IMO we should use ReactNode
instead of ReactElement
actions?: ReactElement | ComponentType | false; | |
actions?: ReactNode | ComponentType; |
I'd go even further and would say that the getElement
implementation is currently too restrictive.
According to the React docs:
Note
isValidElement
checks whether the argument is a React element, not whether it’s a React node. For example,42
is not a valid React element. However, it is a perfectly valid React node.
So to me, the implementation should be the following:
const getElement = (ElementOrComponent: ComponentType | ReactNode) => {
if (isValidElementType(ElementOrComponent)) {
const Element = ElementOrComponent as ComponentType;
return <Element />;
}
return ElementOrComponent;
};
Same applies to other props below.
@fzaninotto @djhi wdyt?
Problem
In order to have a better developper experience we want to simplify the way we customise the
List
sub-component (eg: actions, filters, aside, pagination).Solution
Allow to use React.ComponentType in addition to ReactElement.
or
How To Test
Create a List using a component (
actions={Actions}
)Additional Checks
master
for a bugfix, ornext
for a featureAlso, please make sure to read the contributing guidelines.