React 钩子形式 - 对话框内的字段数组 (Material UI)

React hook form - Field Array inside Dialog (Material UI)

所以我有一个表单,其中包含我通过来自 react-hook-form 的字段数组添加的自定义字段。 一切正常,但我为 属性 项添加了拖放(以重新排序),现在直接显示所有这些字段会很麻烦,所以我将它们移动到对话框中。

这些图片让您了解什么更容易拖放...(正确的)

问题是字段数组值在模式关闭后“重置”(在我在编辑模式中键入这些表单值之后),我想这与重新渲染有关,但我不确定。

我试图在此处展示没有 d&d 和其他无用内容的最小代码示例...
但这里是 codesandbox playground 和完整的代码

CreateCategoryForm.js

const defaultValues = {
  name: "",
  slug: "",
  description: "",
  properties: [] // field array
}

function CreateCategoryForm() {
  const methods = useForm({ defaultValues });
  const { handleSubmit, control, errors } = methods;
  const { fields, append, remove, swap } = useFieldArray({ name: "properties", control });

  const onSubmit = async (data) => {
    console.log("data: ", data);
  };

  return (
    <Container>
        <FormProvider {...methods}>
          <form onSubmit={handleSubmit(onSubmit)} noValidate>
            <FormTextField name="name" />
            <FormTextField name="slug" />
            <FormTextField name="description" />

            {fields.map((card, idx) => (
              <PropertyCard key={card.id} card={card} idx={idx} errors={errors} remove={remove} />
            ))}

            <Button onClick={() => append({ name: "", label: "", type: "text", filterable: true })}>
                Add Property
            </Button>

            <FormSubmitButton>
              Create Category
            </FormSubmitButton>
          </form>
        </FormProvider>
    </Container>
  );
}

PropertyCard.js

function PropertyCard({ card, errors, idx, remove }) {
  const [dialogOpen, setDialogOpen] = React.useState(false);

  const handleOpenDialog = () => {
    setDialogOpen(true);
  };

  const handleCloseDialog = () => {
    setDialogOpen(false);
  };
 
return (
    <div>
      Property {idx + 1}
      <IconButton onClick={() => handleOpenDialog()}>
        edit
      </IconButton>
      <IconButton onClick={() => remove(idx)}>
        X
      </IconButton>

      <Dialog
        fullScreen
        open={dialogOpen}
        onClose={handleCloseDialog}
      >
        <Container maxWidth="xs">
          <FormTextField
            name={`properties[${idx}].name`}
            label="Property Name"
          />
          <FormTextField
            name={`properties[${idx}].label`}
            label="Property Label"
          />
          <FormSelect
            name={`properties[${idx}].type`}
            label="Filter Type"
            options={[
              { label: "text", value: "text" },
              { label: "bool", value: "bool" }
            ]}
            defaultValue="text"
          />
          <FormSwitch
            name={`properties[${idx}].filterable`}
            label="Filterable"
            defaultValue={true}
          />
          <IconButton onClick={handleCloseDialog}>
              X
          </IconButton>
        </Container>
      </Dialog>
    </div>
  );  
}

正如@Bill 在评论中提到的那样,shouldUnregister: false 似乎可以解决问题。

所以我将 useForm 更改为:

const methods = useForm({ defaultValues, shouldUnregister: false });

并且对于每个 属性 输入,我都添加了 defautlValue 以使其工作。

<FormTextField
  name={`properties[${idx}].name`}
  label="Property Name"
  defaultValue={getValues()?.properties?.[idx]?.name} // added this
/>
<FormTextField
  name={`properties[${idx}].label`}
  label="Property Label"
  defaultValue={getValues()?.properties?.[idx]?.label} // added this
/>
<FormSelect
  name={`properties[${idx}].type`}
  label="Filter Type"
  options={[
    { label: "text", value: "text" },
    { label: "bool", value: "bool" }
    ]}
  defaultValue={getValues()?.properties?.[idx]?.type || 'text'} // added this
/>