Skip to content
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

[Regression] CreateButton and ShowButton don't update on 'to' prop change #8671

Closed
rkfg opened this issue Feb 21, 2023 · 12 comments · Fixed by #8741
Closed

[Regression] CreateButton and ShowButton don't update on 'to' prop change #8671

rkfg opened this issue Feb 21, 2023 · 12 comments · Fixed by #8741

Comments

@rkfg
Copy link
Contributor

rkfg commented Feb 21, 2023

What you were expecting:
See #5014 and #5483 where it was fixed, the CreateButton component should rerender if the to prop changes, it was fixed and then this check (prevProps.to === nextProps.to) was removed in 4c9bfb4. If this is not officially supported now (the docs link mentioned in #5008 (comment) returns 404 now) how do I prefill forms using Create button? defaultValues for SimpleForm don't work here because I need those values from the List context (such as filter values) which isn't available in Create/Show/Edit views. Lifting them up seems like an overkill for such a trivial task. I realize that to is an object so it may cause excessive rerenders due to referential inequality if it's not memoized by itself, maybe it's better to compare its individual fields instead.

What happened instead:
I'm not sure if it was intentional or by mistake, now I can't reliably prefill the form from filter values as described in #5008 (comment) by myself. The button "lags" by one render, i.e. it prefills the previous values and when I go back and forward it sets the actual value.

Steps to reproduce:
https://codesandbox.io/s/nervous-driscoll-1oetd4

  • add a new filter by title on the Posts tab
  • type anything in the filter or leave it filled by default
  • press Create
  • the title field in the Create view is empty
  • go back in the small browser window
  • press Create again
  • the title field is now filled as expected
@slax57
Copy link
Contributor

slax57 commented Feb 21, 2023

Hi, and thank you for this very detailed report.

I believe the idea of the CreateButton and ShowButton is mainly to provide simple shortcuts to the create and show pages.
Basically when you are passing pathname: '/posts/create' to the CreateButton you are in fact re-doing what the button does.

If you need more control over the redirection, I believe the recommended way (which is actually not much more complex) would be to use a MUI Button directly instead.
This is what we recommend for instance when Linking To A Pre-Filtered List.

So IMO I don't think it would be desirable to have the CreateButton support this use-case, but rather we should encourage the use of a simple MUI Button in this case.

That being said, I would like to have @fzaninotto or @djhi 's opinion to back me up on this one.
Any thoughts guys?

@slax57
Copy link
Contributor

slax57 commented Feb 21, 2023

Actually we even document this use-case in the docs here: https://marmelab.com/react-admin/Create.html#prefilling-the-form
And here as well, we recommend to use a MUI Button

@rkfg
Copy link
Contributor Author

rkfg commented Feb 21, 2023

Thank you, that worked. However, those examples refer to MUI button which doesn't have neither component nor to props, maybe they still work in JS but TS throws an error. I replaced it with RA's Button wrapper and that did the trick, except the label and icon should go into props and not child text node. Am I doing something wrong? My MUI version is 5.11.10, the latest one.

@slax57
Copy link
Contributor

slax57 commented Feb 21, 2023

@rkfg that's wierd because we use this in our own demos (which have TS enabled) without running into any issues.
E.g. https://github.com/marmelab/react-admin/blob/master/examples/demo/src/segments/LinkToRelatedCustomers.tsx
Our MUI version is 5.2.8

@rkfg
Copy link
Contributor Author

rkfg commented Feb 21, 2023

Oh okay, it was because the react-router-dom's Link prop to doesn't have the state field which is convenient for this purpose. This content of to:

                            state: {
                                record: {
                                    dept_id: filterValues?.dept_id,
                                },
                            },

looks better than this:

search: `filter=${JSON.stringify({ dept_id: filterValues?.dept_id })}`,

while both are functionally identical in this case. The former doesn't change the button link and less error-prone imo. But it only works with RA's button, not the MUI's. I honestly preferred the former behavior because I could customize just one aspect of this button without recreating it from scratch (label, icon, color, size etc.).

@slax57
Copy link
Contributor

slax57 commented Feb 21, 2023

I tend to agree.
But still, on my end, passing a state prop to a MUI Button using react-router-dom's Link as underlying component is perfectly fine.

            <Button
                component={Link}
                to={{
                    pathname: '/comments/create',
                }}
                state={{ record: { post_id: 123 } }}
            >
                Write a comment for that post
            </Button>

What is your react-router-dom version? We are on react-router-dom@6.2.1.

@rkfg
Copy link
Contributor Author

rkfg commented Feb 21, 2023

Ok, got it. I was passing state as a field of to and here you're passing it as an individual prop. That way it definitely works. There are still some small issues with this solution:

  • I need to manually do translation with useTranslate
  • the button isn't well aligned with other default buttons such as the filter button or export (there's a lineHeight style fix in StyledButton but it's not exported)
    So yes, it's doable but the efforts are inappropriate for such a simple task, especially since it worked fine before and still does (after patching the props equality check function).

@slax57
Copy link
Contributor

slax57 commented Feb 23, 2023

@rkfg Okay, so let's add back the to prop as one of the memoized component's dependencies.
I believe we can leverage lodash's isEqual to help us compare the values, since they will likely be complex objects.
Would you like to provide a PR to implement this?

@rkfg
Copy link
Contributor Author

rkfg commented Feb 23, 2023

Should be easy to add but I can't take a closer look until next week (or a week after that). If anyone's up to it feel free to fix it, or wait until then.

@IAmVisco
Copy link
Contributor

IAmVisco commented Feb 26, 2023

Not sure if related at all but since Link was suggested wanted to chip in and mention that <Button component={Link} ... /> throws MUI warnings in my console: Warning: Failed prop type: Invalid prop component supplied to ForwardRef(ButtonBase2). Expected an element type that can hold a ref. Did you accidentally provide a plain function component instead? For more information see https://mui.com/r/caveat-with-refs-guide and Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()? Check the render method of MuiButtonBaseRoot. The button still works fine but would be nice to clean this up if that's possible with MUI.

@slax57
Copy link
Contributor

slax57 commented Feb 27, 2023

@IAmVisco I do not see this warning in the simple example, although we are using the CreateButton and EditButton, which both use <Button component={Link} ... /> internally.
Where did you see it?

@IAmVisco
Copy link
Contributor

I thought it was an common issue seeing it was from MUI... Sorry for the confusion. I will prepare a reproducible sandbox and open a proper issue later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants