primefaces / primereact

The Most Complete React UI Component Library
https://primereact.org
MIT License
6.84k stars 1.04k forks source link

Criticism and Suggestion: PrimeReact Form API #1938

Closed NathanPB closed 2 years ago

NathanPB commented 3 years ago

I'm submitting a ... (check one with "x")

[ ] bug report
[ x ] feature request
[ ] support request => Please do not submit support request here, instead see https://forum.primefaces.org/viewforum.php?f=57

I have been using PrimeReact for about 2 years now, it just replaced every other component library that I was using before and the work made here is amazing. However, it has downsides.

Just an abstract: This text wall will describe the problem of creating extensive forms with PrimeReact and give some ideas to solve it.

My criticism to PrimeReact:

The one that (imo) sucks the most is creating forms with PrimeReact. Really, you need to write something like this to get a form working:

const [value, setValue] = React.useState(0)

return (
  <InputNumber
    value={value}
    onValueChange={e => setValue(e.value)}
  />
)

This actually looks fine, but it takes at minimum 5 lines to write a form field (if you are a decent human being that indents things). If we have a form with 5 fields, we will need a minimum of 5 * 5 + 2 (2 for <> and </>) lines. This not counting the display structure (which primeflex does a great work helping), but I don't wanna touch display here.

Other problem that I see here is that for every single field you will have to allocate two names in the component context (e.g. value, setValue), and this can easily get messy and lead yourself to get lost into your variable names and the context that each one belongs.

The even worst: onChange hell

This is not all, you could simply copy/paste this boilerplate and it would be less bad. But then we got <InputText/> that does not use onValueChange, but onChange instead. It also will need e => e.target.value instead of e => e.value. And then there are checkboxes that uses e => e.checked, and calendars that use other messy things that I can't remember, and on and on and on.

The problem that I want you to understand here is that primereact forms has a heavy leak of standardizing, and this does not help with the form problem. And I honestly understand that, we cannot expect the output of a calendar that selects a range of dates to output a number. But onChange and onValueChange for the same component? I can't even tell what's the difference without looking into the docs.

So what? Do we create InputText and UncontrolledInputText?

No, we just standardize all the input components to use onValueChange, keeping the { originalEvent, value, target } scheme for all the input components that will be supported by the Form API. This includes adding onValueChange to components that do not support it and fixing the mess around value and checked in the Checkbox component, for instance.

This way we will be able to create a generic API to make the existing controlled components automagically have its state managed by primereact, this will also work with any component that follows the value, onValueChange, { originalEvent, value, target } scheme on props, including external components that does not belong to primereact.

So what?

Based in awesome works on others react form libraries I will be describing here what I, my person, myself, me would like to have as a solution.

useFormField

This hook will control the state of a single input component, useful when you do not have a very extensive form, but just a field around. I have three different alternatives to purpose:

Alternative A

const value = useFormField()

return (
  ... my beautiful form lalalalalala ...,
  { withForm(value, <InputText ... />) }
)

Alternative B

const value = useFormField()

return (
  ... my beautiful form lalalala ...,
  { value.input(<InputText ... />) }
)

Alternative C

const value = useFormField(<InputText ... />)

return (
  ... you got this ...,
  { value }
)

Then, you can access the value with value.value (I know this is not looking aesthetically good, it's because I had the brilliant idea to name the value "value"). I think JavaScript can do some reflection hacks to make it look even better with the prototype-based object orientation, but I will not get deeper on this.

useForm

The useFormField hook does solve some problems, but it is still requiring to allocate one name in the context to each field in the form, so we gotta create a useForm hook that is basically a multiple useFormField. Unfortunately React does not allow to dynamically call hooks, so it cannot directly delegate the implementation of useFormField.

Alternative A

const form = useForm()

return (
  <>
  { form.input('first_name', <InputText ... />) }
  { form.input(<InputNumber name="age" ... />) /* Maybe using the "name" property */ }
  { form.input('stupidity_rate', <Rating ... />) }
  </>
)

Alternative B

const form = useForm()

return (
  <>
  { withForm(form, 'first_name', <InputText ... />) }
  { withForm(form, <InputNumber name="age" ... />) /* Maybe using the "name" property */ }
  { withForm(form, 'stupidity_rate', <Rating ... />) }
  </>
)

Whats Next

I can see some more useful features that can be done on it:

(Finally) Finalizing:

This got pretty long, I wrote it in a kinda informal language, so it doesn't get boring to me to write, neither to readers to read.

This would take a great effort to implement, but the changes will surely be appreciated by the PrimeReact community (me included). I am available to help write this feature if the team decides that it's a good idea to do so.

melloware commented 2 years ago

@NathanPB Isn't this what the 3 validation examples already do with well documented and extremely functional libraries? For example everything you have described is this example: https://primefaces.org/primereact/reacthookform/ No?

Real-Gecko commented 2 months ago

https://primefaces.org/primereact/reacthookform/

It leads to 404

melloware commented 2 months ago

yes they removed all React Hook Form and Formik examples....

Real-Gecko commented 2 months ago

Are there any fresh examples?

melloware commented 2 months ago

I have a fully running RHF with PrimeReact demo here: https://github.com/melloware/quarkus-primereact

The RHF code you are interested in is right here: https://github.com/melloware/quarkus-primereact/blob/main/src/main/webui/src/CrudPage.tsx

But I suggest running the demo to see it in action.

Real-Gecko commented 2 months ago

Great, thank you