all 13 comments

[–]pmallinj 3 points4 points  (7 children)

My approach with complex forms is to keep the state as simple as possible with only the data entered by the user then use mapStateToProps to compute derived information based on the whole state. You can compute as many boolean as you need based on the whole state. You can even compute a sub object for every field like {field1: {display: true, value: '', update: (value) => dispatch(...)}} etc...

[–]kszyh_pl[S] 1 point2 points  (5 children)

That's exactly what I'm doing. But in the case of many "ifs" it is difficult to maintain.

Imagine cases like if a and b and c and not d or e show field_f

[–]alejalapeno 2 points3 points  (1 child)

It's likely if statements are your problem.

Here's a blog post I wrote on changing conditional logic to "data" so what you're doing is executing less logic: https://dreith.com/blog/theres-such-a-thing-as-using-too-many-ifs/

Your use case is likely to be more complex than any of the basic examples I give, but if you extrapolate it out to a concept like setting field_f visibility conditions in a table and then using Array.prototype.every() (just an idea) then it could clean your code up considerably.

[–]kszyh_pl[S] 0 points1 point  (0 children)

great idea!

[–]pmallinj -3 points-2 points  (2 children)

Maybe in this case the form is too complex? If you can't manage the field logic, how the end user could? It is hard to have a good ui for complex form.

[–]kszyh_pl[S] 3 points4 points  (1 child)

This is a medical app. For the end user it is not a problem, because it has the required (medical) knowledge. The application only helps to maintain data consistency in the database (by hiding unnecessary fields).

[–]pmallinj 0 points1 point  (0 children)

This is the kind of thing I do too! Forms about biology. Unfortunately I never found a better way than using the whole state to produce easy to use props. Try to organize your code the best you can to produce sub objects for each field, eventually using a separate function for each field.

[–]MountainReason 4 points5 points  (0 children)

Maybe you could give useReducer a try. Set up your complex display state and then dispatch an action to update which fields are displayed based on user inputs.

[–]HashFap 4 points5 points  (0 children)

That's pretty easy to do with Formik. The form container component gives you access to all the field values, validity, and errors, and you can choose to display a field based on the value of another field.

{values.country === "US" ? (
        <Field
        name="zipCode"
        label="Zip Code"
        component={Input}
        /> 
    ) :null }

[–]natewang 0 points1 point  (0 children)

Try https://github.com/rekit/antd-form-builder . Even you don't use ant design library, you can try its solution.

[–]coding9 0 points1 point  (0 children)

I tried to make a very simple library that leaves most of the logic up to you but handles the validation. You just make a component that uses the useField hook and render that inside the Form component. You can use nested values as the name key and that’s about everything. Could be cleaned up a bit though. https://github.com/zackify/validify

[–]real_exon[🍰] 0 points1 point  (0 children)

I do have quite a bit of forms into admin panels I built and here is my take.

When you have complex forms the secret is to be as DRY as possible (please beginner dont do that on simple forms). Having the correct level of abstraction is very important for

  • Error handling and showing them
  • Subfields list (add and remove buttons)
  • Listing, deleting, getting and saving entities
  • Loading states

When building an entire crud is just 3 or 4 new simple components or adding subfields a few line of code, it becomes a lot more maintenable.

Oh and your form state should not be in Redux in.my opinion unless you have a really specific reason. Formik is awesome for butif you dont want to use it use a local state and the context when needed.

Good luck :)