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

Make modals/forms more reactive #5897

Merged
merged 20 commits into from
Nov 20, 2023

Conversation

wolflu05
Copy link
Contributor

@wolflu05 wolflu05 commented Nov 10, 2023

This PR aims to make the modals and forms framework more reactive.

  1. Separates ApiForms from modals so that they can be used on their own
  2. Makes it possible to hook into the modal state and build some custom reactive things

This is already working, but it is a bit slow. I think this is caused by multiple reasons. The biggest is, that Form fields get passed every form state as props. That means they rerender on every change. But actually that is not needed. Because e.g. changing the value of a text input should not rerender the part category select input. The part category select input should only rerender if its definition changes. (This can be easily seen by placing console.log("Rerender", definition.label) inside of the ApiFormField)

EDIT: I now discovered, that the preview production build doesn't has that much of performance issues, and checking out the latest master in development has even more performance problems on my side.

Todo

Edit tasklist title
Beta Give feedback Tasklist Todo, more options

Delete tasklist

Delete tasklist block?
Are you sure? All relationships in this tasklist will be removed.
  1. fix onValueChange issue
    Options
  2. migrate to react-hook-form
    Options
  3. improve initial data fetching query
    Options
  4. Loading existing value into Related model field does not work
    Options
  5. Remove unnecessary things from onValueChange callback parameters
    Options
  6. use isDirty state for disabling the submit button
    Options
  7. implement nested object field
    Options
  8. implement dependent field field (Printing dialog needs to be implemented first)
    Options
  9. validate that all fields work, especially a choices field
    Options
  10. fix TS errors
    Options
  11. Check TODO: comments
    Options

Copy link

netlify bot commented Nov 10, 2023

Deploy Preview for inventree-web-pui-preview ready!

Name Link
🔨 Latest commit 8b8ee1c
🔍 Latest deploy log https://app.netlify.com/sites/inventree-web-pui-preview/deploys/655b3f263604b90008894d9d
😎 Deploy Preview https://deploy-preview-5897--inventree-web-pui-preview.netlify.app/
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 100 (no change from production)
Accessibility: 86 (no change from production)
Best Practices: 92 (no change from production)
SEO: 70 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify site configuration.

# Conflicts:
#	src/frontend/src/components/forms/ApiForm.tsx
#	src/frontend/src/pages/Index/Playground.tsx
@wolflu05
Copy link
Contributor Author

wolflu05 commented Nov 10, 2023

@SchrodingersGat Please let me know what you think about this implementation, how you feel the performance of the new form on your side compared to latest master. And if we need to improve performance in this PR. In my testing it feels like the latest master has more performance problems than this when running both in dev mode. Trying the production/preview build seems like it is working not really noticeable that there are some lags.

@wolflu05 wolflu05 added refactor Platform UI Related to the React based User Interface labels Nov 10, 2023
@SchrodingersGat
Copy link
Member

@wolflu05 nice, I'll check this out next week - I am away for the weekend :)

@wolflu05 wolflu05 mentioned this pull request Nov 13, 2023
@SchrodingersGat
Copy link
Member

@wolflu05 very nice - I like the demo example in the "playground" area :)

@wolflu05
Copy link
Contributor Author

wolflu05 commented Nov 13, 2023

Thank you @SchrodingersGat that you like it. The reactive approach (where the active switch disables the keyword input) with the inline form without a modal can also be used the same way for the modal form with the hook.

What do you suggest for going forward with this PR? Do you see some performance issues compared to the old implementation? (Make sure to only compare a dev version with a dev version and a build with a build, they have huge differences in my tests.)

@SchrodingersGat
Copy link
Member

I did not see any performance issues, I have not profiled each implementation.

Do you have a set of features you still want to implement here?

@wolflu05
Copy link
Contributor Author

No, I have nothing else planned for this PR. Was just not sure if there is some more work required regarding performance. But if you say it's fine, then refactoring the field component to not rerender everytime would be another task.

What is your plan on using the new hook syntax? Should we refactor and remove the old implementation? Or should we just use the new hook implementation for the new forms, or only the ones require reactivity?

@SchrodingersGat
Copy link
Member

But if you say it's fine, then refactoring the field component to not rerender everytime would be another task.

Would you be willing to take on this one? I think that you have a better idea where to look than I do.

What is your plan on using the new hook syntax? Should we refactor and remove the old implementation? Or should we just use the new hook implementation for the new forms, or only the ones require reactivity?

Can you please submit a PR with an example of refactoring one of the existing forms? I would rather do them all "properly" and refactor what we have now, before we build out a lot more forms.


If you are happy with this, please mark as ready and I will merge

@wolflu05
Copy link
Contributor Author

wolflu05 commented Nov 15, 2023

Would you be willing to take on this one? I think that you have a better idea where to look than I do.

I tried to eliminate unnecessary dependencies in my last PR, but it seems like the useForm hook from mantine has some issues, see this discussion. The best way to fix this issue and improve performance would be like they recommend in the discussion to switch to another form state library like react-hook-form. I previously already worked with that library.

Can you please submit a PR with an example of refactoring one of the existing forms? I would rather do them all "properly" and refactor what we have now, before we build out a lot more forms.

Sure, I can refactor the old forms in a followup PR if you want.

@wolflu05
Copy link
Contributor Author

wolflu05 commented Nov 15, 2023

I now committed a first draft of switching to the react-hook-form lib. In my tests the performance now has drastically improved. I already planned the code so that the integration of the nested object and dependent field type become very easy. @SchrodingersGat Please let me know what you think about the move to another form state lib. I attached two screen recordings which shown the performance improvements.

Performance comparison

Old

Bildschirmaufnahme.2023-11-15.um.21.46.48.mov

New

Bildschirmaufnahme.2023-11-15.um.21.47.28.mov

@SchrodingersGat
Copy link
Member

@wolflu05 looking very nice :)

@wolflu05 wolflu05 marked this pull request as ready for review November 16, 2023 18:42
@wolflu05
Copy link
Contributor Author

wolflu05 commented Nov 16, 2023

@SchrodingersGat This would be ready for review now. I decided to implement the dependent field not yet, as 1. the diff is already large enough and 2. it would be better to build the print label dialog first. That would be the easiest think to test the dependent field then while implementing it. But that is a too big task for here.

I now switched to the already mentioned react-hook-form library which drastically improves performance. I already changed a few forms that required a touch because they were incompatible with the new approach of not passing the form object down but rather using the powerful react features. For the rest of the forms I don't have the time now, because I want to finish the machine integration soon.

I also implemented nested object fields now and added the initial_stock and initial_supplier fields to the part create dialog.

Copy link
Contributor

@matmair matmair left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work; works very well on my laptop and iPad!

src/frontend/src/contexts/LanguageContext.tsx Outdated Show resolved Hide resolved
@SchrodingersGat
Copy link
Member

After reviewing these changes in #5947 I am quite happy with this implementation - these are great forward steps :)

Please keep this great work coming @wolflu05

@SchrodingersGat SchrodingersGat merged commit cb53778 into inventree:master Nov 20, 2023
24 checks passed
Comment on lines +205 to +209
const oldFormSuccess = props.onFormSuccess;
props.onFormSuccess = (data) => {
oldFormSuccess?.(data);
modals.close(modalId);
};
Copy link
Contributor Author

@wolflu05 wolflu05 Nov 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SchrodingersGat To continue this conversation here. This is just a name, because I need to wrap the onFormSuccess function so that I can do something else and also call the callback provided in props. If I wouldn't save this in a variable, and just call it from inside, I would have an endless recursion.
image

@wolflu05 wolflu05 deleted the pui-reactive-forms branch February 15, 2024 14:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Platform UI Related to the React based User Interface refactor
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants