Good practices for using the same form components for both create and edit pages

Viewed 670

I have this crowded form with some 30-40 fields, and most of them have kinda complex logic. Understandibly I wanted to make these form areas reusable for both create and edit pages since both are identical in terms of form items and fields. I got them to work without much effort, and they work fine for most parts, except the quest for reusability introduced some other challenges and now I am questioning if it's worth it.

For me some of the challenges of using the same forms for both create and edit are:

  • Conditionals everywhere. Want to make a field uneditable in edit mode? Extra props to pass in and disable said fields with those props.

  • Edit mode needs initial state so forms fields are filled in with existing data but create page does not like that, so even more and even worse conditions like:

const { user } = React.useContext(DetailContext) ?? {}; // I know...
const [userType, setUserType] = useState(user?.user_type ?? null); // yep

At this point I can't even decide how to safely assign and use stuff, and I can't estimate what parts are prone to breaking.

Is this inevitable and fine as is or is this complete silliness? What are some good practices for making form areas or forms reusable? Can I reduce noise without sacrificing reusability?

1 Answers

The question is indeed kind of broad but a general solution might still help you. There are a couple of main points you need to consider:

  1. Are all the fields present in both edit and create mode or there might be situations where not all of them are included in either?
  2. Are there fields that are supplied on creation but cannot be edited after that(in edit mode)?
  3. Are there initial values for any of the creation form fields?

I would tackle the problem in the following manner:

You'll have a single form component which accept field properties as parameter(component props). For each field you supply the following information:

  1. Initial value, if any (initialValue)
  2. If the field should be present in the form at all (isDisplayed)
  3. If the field should be present but disabled (isDisabled)

This way you cover all of the previously mentioned points while keeping a single form component. Also, you'll supply a parameter like mode with possible values edit/create which guides the form logic and how the form submit would be handled(difference in handling logic, different endpoints and such). Then, in your form component you'll have to do some checks based on the provided parameters i.e. should the given form input be disabled if isDisabled is true or if it should be displayed at all - isDisplayed.

It's not a perfect solution, but it is flexible enough to enable you to use the same form template and share most of the handling logic. If, however, you have vast differences in how the edit/create forms are structured, you might be better off to duplicate some logic by introducing two separate components but save your sanity and time figuring out how to cover and abstract every single new extenstion you want to introduce in one of them.

Related