seasonedcc / remix-forms

The full-stack form library for Remix and React Router
https://remix-forms.seasoned.cc
MIT License
492 stars 25 forks source link

field param of useFieldArray not being updated in real-time and out of date when passed to modal #197

Closed paulm17 closed 1 year ago

paulm17 commented 1 year ago

I have a pretty complex example. The code is below.

The problem I am having is that the fields are not getting updated in real-time. Only when lifecycle happens again, do they get populated. For example, if I add another option.

I've tried using register and setValue. But it refuses to work.

Any ideas?

Is there a sandbox that I could use, I'd be happy to make a simplified example if that helps.

Form:

  {({ Field, Errors, Button, formState, control, watch }) => (
    <Field name="options" type="array">
      {({ Errors }) => (
        <>
          <ProductOption control={control} />
          <Errors />
        </>
      )}
    </Field>
  )}

ProductOption component:

function ProductOption({ control }: productOptionProps) {
  const { fields, append, remove } = useFieldArray({ control, name: "options" })

  return (
    <Stack>
      {fields.map((field, index: number) => {
        return (
          <ProductOptionItem
            key={field.id}
            field={field}
            index={index}
            control={control}
            onDelete={() => remove(index)}
          />
        )
      })}   
    </Stack>
  )
}

ProductOptionItem:

function ProductOptionItem({
  index,
  field,
  control,
  onDelete,
}: productOptionItemProps) {
  const [opened, { open, close }] = useDisclosure(false)
  const onMore = () => {
    open()
  }

  return (
    <>
      <Group
        sx={{
          alignItems: "end",
        }}
      >
        <FormInput
          control={control}
          name={`options.${index}.name`}
          placeholder="e.g. Color, Size"
        />

        <Box
          sx={{
            flex: 1,
          }}
        >
          <FormTagPicker
            control={control}
            name={`options.${index}.tags`}
            placeholder="Separate values with a comma"
          />
        </Box>
jamalsoueidan commented 1 year ago

I was looking around to use this package, but then i saw the same error is happening to you. https://github.com/airjp73/remix-validated-form/issues/279

For me in the other package the problem was with the key.

paulm17 commented 1 year ago

@jamalsoueidan Thanks for replying. Appreciate it.

Actually, I am incorrect about the problem 😓. The main form object updates all the time. There are no problems.

The issue is that I have a nested form, which I am passing in the field param which should contain all the values. When I pass them along. They are out of date.

I have noticed, that if I don't use a form and instead pass through the control function. Everything seems fine, but I want a nested form.

Anyway. That's the main issue I think. 🤔

paulm17 commented 1 year ago

Ok, sorted the problem.

ProductOptionItem:

function ProductOptionItem({
  index,
  control,
  onDelete,
  setValue,
}: productOptionItemProps) {
  ...

  return (
    <>
      <Group
        sx={{
          alignItems: "end",
        }}
      >
        ...
      </Group>
      <Modal
        ...
      >
        <OptionModal
          index={index}
          control={control}
          onSubmit={values => onSubmit(values)}
          close={close}
        />
      </Modal>
    </>
  )
}

The modal is inheriting the control from the parent form. I'm also passing on the index of the field. So that the modal has the correct item in the array.

In the modal:

function OptionModal({ index, control, onSubmit, close }: optionModalProps) {
  const { fields } = useFieldArray({ control, name: "options" })

  return (
    <Form
      labelComponent={MantineFormLabel}
      inputComponent={MantineFormInput}
      buttonComponent={MantineFormButton}
      schema={OptionFormSchema as any}
      values={fields[index]}
      onSubmit={values => onSubmit(values)}
    >
    ...
    </Form>
}

When the modal instantiates it retrieves the field object with useField array and then with the index, assigns the correct object to the Form values (default/initialValues).

Now the form behaves correctly 😄