我做了一个小的codesandbox,它有一个可重复的bug here,我有一个表单组件,我在那里用初始值设置useForm钩子,表单有一个IncomeInfo
和一个数组字段组件作为子组件:
const { pageFormValues, setPageFormValues, setActiveStep } = usePageProvider();
const initialValues = pageFormValues ?? createInitialValues(income);
const [action, setAction] = useState<ActionStatus>(ActionStatus.IDLE);
const useFormMethods = useForm({
defaultValues: initialValues,
});
return (
<FormProvider {...useFormMethods}>
<form onSubmit={useFormMethods.handleSubmit(onSubmit)}>
<IncomeInfo />
<IncomeBaseTable initialValues={initialValues} />
IncomeBaseTable
看起来像这样:
export const IncomeBaseTable = ({ initialValues }) => (
<TableWrapper heading={["Period", "Employer", "Total", ""]}>
<ArrayField
name="incomeBase"
children={({ index, handleRemove, handleAppend }) => (
<TableRowWrapper
cells={[
<div className="flex gap-x-4">
<FormControlledDatePicker
key={`incomeBase[${index}].from`}
name={`incomeBase[${index}].from`}
label="From"
placeholder="DD.MM.ÅÅÅÅ"
defaultValue={initialValues.incomeBase[index].from}
hideLabel
/>
<FormControlledDatePicker
key={`incomeBase[${index}].to`}
name={`incomeBase[${index}].to`}
label="To"
placeholder="DD.MM.ÅÅÅÅ"
defaultValue={initialValues.incomeBase[index].to}
hideLabel
/>
</div>,
<FormControlledTextField
key={`incomeBase[${index}].employer`}
name={`incomeBase[${index}].employer`}
label="Employer"
hideLabel
/>,
<FormControlledTextField
key={`incomeBase[${index}].total`}
name={`incomeBase[${index}].total`}
label="Total"
type="number"
hideLabel
/>,
<Button
key={`delete-button-${index}`}
onClick={() => handleRemove(index)}
icon={<Delete aria-hidden />}
variant="tertiary"
size="xsmall"
/>,
]}
/>
)}
/>
</TableWrapper>
);
TableWrapper
看起来像这样:
export const TableWrapper = ({ heading, children }: { heading: string[]; children: ReactNode }) => (
<Table size="small">
<Table.Header>
<Table.Row>
{heading.map((header) => (
<Table.HeaderCell scope="col" key={header}>
{header}
</Table.HeaderCell>
))}
</Table.Row>
</Table.Header>
<Table.Body>{children}</Table.Body>
</Table>
);
export const TableRowWrapper = ({ cells }: { cells: ReactElement[] }) => (
<Table.Row>
{cells.map((cell, index) => {
if (!index)
return (
<Table.HeaderCell scope="row" key={cell.key}>
{cell}
</Table.HeaderCell>
);
return <Table.DataCell key={index}>{cell}</Table.DataCell>;
})}
</Table.Row>
);
当我像这样从IncomeInfo
追加到field数组时,值会被更新,但是field和追加操作之前是一样的:
const { control, getValues } = useFormContext();
const { append, remove } = useFieldArray({
control,
name: "incomeBase",
});
const handleOnChange = (checked, incomeValues) => {
if (checked) {
append({
from: null,
to: null,
employer: "",
total: incomeValues.sum,
});
}
};
当我登录ArrayFields
组件时,我可以看到使用getValues
方法获得了新值,但fields
没有更新:
const ArrayFields = ({ name, children }: ArrayFieldsProps) => {
const { control, getValues } = useFormContext();
const { fields, append, remove } = useFieldArray({
control,
name: name,
});
const handleAppend = (value) => {
append(value);
console.log("add: ", getValues());
};
const handleRemove = (index) => {
remove(index);
console.log("remove: ", getValues());
};
console.log("field", fields);
console.log("value", getValues().incomeBase);
由于字段未更新,因此新字段未呈现。为什么值更新,而字段未更新?
如果我从IncomeBaseTable
组件追加数组字段,那么它会追加并重新呈现新字段:
export const IncomeBaseTable = ({ initialValues }) => (
<TableWrapper heading={["Period", "Employer", "Total", ""]}>
<ArrayField
name="incomeBase"
children={({ index, handleRemove, handleAppend }) => (
<TableRowWrapper
cells={[
<div className="flex gap-x-4">
<FormControlledDatePicker
key={`incomeBase[${index}].from`}
name={`incomeBase[${index}].from`}
label="From"
placeholder="DD.MM.ÅÅÅÅ"
defaultValue={initialValues.incomeBase[index].from}
hideLabel
/>
<FormControlledDatePicker
key={`incomeBase[${index}].to`}
name={`incomeBase[${index}].to`}
label="To"
placeholder="DD.MM.ÅÅÅÅ"
defaultValue={initialValues.incomeBase[index].to}
hideLabel
/>
</div>,
<FormControlledTextField
key={`incomeBase[${index}].employer`}
name={`incomeBase[${index}].employer`}
label="Employer"
hideLabel
/>,
<FormControlledTextField
key={`incomeBase[${index}].total`}
name={`incomeBase[${index}].total`}
label="Total"
type="number"
hideLabel
/>,
<Button
key={`add-button-${index}`}
onClick={() => handleAppend(fieldInitialValues)}
icon={<Add aria-hidden />}
variant="tertiary"
size="xsmall"
/>,
]}
/>
)}
/>
</TableWrapper>
);
为什么当我从IncomeBaseTable
追加时,它会添加到字段数组并重新呈现,而当我从IncomeInfo
组件追加时,它不会?
更新
我在父组件中使用useArrayField
的一个示例,然后将其作为一个 prop 传递给子组件,从而使其工作。当我有多个示例具有相同的字段名称时,它将不工作。不知道为什么,如果我需要将其作为一个 prop 传递,则会破坏作为一个钩子的目的。
2条答案
按热度按时间taor4pac1#
react-hook-form
在幕后使用proxies来减少渲染的数量。在您的情况下,您可以更新钩子useArrayField
之外的字段。这个钩子有自己的方法来检测更改,并且不期望外部更改。您可以将
useArrayField
值转发到<IncomeInfo/>
或使用useWatch()
获取字段值。**EDIT:**文档最后一节有一个很好的示例(受控字段数组):https://react-hook-form.com/api/usefieldarray/
eufgjt7s2#
我建议从
useFormContext
本身获取fields
或updated fields
,以便您可以访问form context
或updated fields
。下面是
IncomeInfo
,您将在其中追加字段在
IncomeBaseTable
中获取fields
,需要借助getValues()
重载方法,特别是getValues(name?: name)
。Check the fix here