如何解决多级嵌套对象
最近我发现了react-hook-from插件,由于其出色的性能,乍看之下似乎非常适合开始使用和替换其他插件。
在将插件用于某些非常简单的表单后,我遇到了一个我希望使用该插件处理的复杂表单。我的表单基于具有以下结构的嵌套对象。 (打字稿定义)
type model = {
tag: string;
visible: boolean;
columns?: (modelColumn | model)[];
}
type modelColumn = {
property: string;
}
因此,为了处理n级嵌套表单,我创建了以下组件。
const initialData = {
...
datasource: {
tag: "tag1",visible: true,columns: [
{
property: "property",},{
property: "property1",{
tag: "tag2",columns: [
{
property: "property",{
tag: "tag3",visible: false,columns: [
{
property: "property",}
]
}
]
},{
entity: "tag4",}
],...
}
export const EditorContent: React.FunctionComponent<EditorContentProps> = (props: any) => {
const form = useForm({
mode: 'all',defaultValues: initialData,});
return (
<FormProvider {...form}>
<form>
<Handler
path="datasource"
/>
</form>
</FormProvider>
);
}
在上面的组件中,创建了带有初始数据的主窗体。 (我提供了一个示例值)。 Handler
组件具有路径属性的递归登录名,以调用表单数据类型的嵌套逻辑。这是示例实现。
...
import { get,isNil } from "lodash";
import { useFieldArray,useForm,useFormContext,useWatch } from "react-hook-form";
...
export type HandlerProps = {
path: string;
index?: number;
...
}
export const Handler: React.FunctionComponent<HandlerProps> = (props) => {
const { path,index,onDelete,...rest } = props;
const { control } = useFormContext();
const name = isNil(index)? `${path}` :`${path}[${index}]`;
const { fields,append,insert,remove } = useFieldArray({
control: control,name: `${name}.columns`
});
...
const value = useWatch({
control,name: `${name}`,});
...
const addHandler = () => {
append({ property: null });
};
console.log(`Render path ${name}`);
return (
<React.Fragment>
<Row>
<Col>
<FormField name={`${name}.tag`} defaultValue={value.tag}>
<Input
label={`Tag`}
/>
</FormField>
</Col>
<Col>
<FormField defaultValue={value.visible} name={`${name}.visible`} >
<Switch />
</FormField>
</Col>
<Col>
<button onClick={addHandler}>Add Column Property</button>
</Col>
</Row>
{
fields && (
fields.map((field: any,_index: number) => {
if (field.property !== undefined) {
return (
<Column
path={`${name}.columns`}
index={_index}
control={control}
fields={fields}
onDelete={() => remove(_index) }
/>
)
} else {
return (
<Handler
path={`${name}.columns`}
index={_index}
/>
)
}
})
)
}
</React.Fragment>
);
}
基本上,如果处理程序组件应呈现诸如datasource.columns [x]形式的嵌套对象,则该组件将使用表单的上下文并调用自身,该寄存器要使用FieldArray来获取其列。到目前为止,一切正常。我正确地渲染了完整的树(如果我可以说)就像对象形式。
作为参考,这里是Column组件的代码,以及formField帮助器组件FormField的代码。
export const Column: React.FunctionComponent<ColumnProps> = (props) => {
const { fields,control,path,onDelete } = props;
const value = useWatch({
control,name: `${path}[${index}]`,defaultValue: !isNil(fields[index])? fields[index]: {
property: null,}
});
console.log(`Render of Column ${path} ${value.property}`);
return (
<Row>
<Col>
<button onClick={onDelete}>Remove Property</button>
</Col>
<Col>
<FormField name={`${path}[${index}].property`} defaultValue={value.property}>
<Input
label={`Column Property name`}
/>
</FormField>
</Col>
</Row>
);
}
export type FormFieldProps = {
name: string;
disabled?: boolean;
validation?: any;
defaultValue?: any;
children?: any;
};
export const FormField: React.FunctionComponent<FormFieldProps> = (props) => {
const {
children,name,validation,defaultValue,disabled,} = props;
const { errors,setValue } = useFormContext();
return (
<Controller
name={name}
control={control}
defaultValue={defaultValue? defaultValue: null}
rules={{ required: true }}
render={props => {
return (
React.cloneElement(children,{
...children.props,...{
disabled: disabled || children.props.disabled,value: props.value,onChange: (v:any) => {
props.onChange(v);
setValue(name,v,{ shouldValidate: true });
},}
})
);
}}
/>
);
}
问题是当我从数组中删除一个字段时。处理程序组件会在fields
数据上重新渲染具有正确值的图像。但是useWatch的值具有初始数据,这会导致呈现错误的渲染并显示错误的字段,从而使表格开始啮合。
是否有关于如何正确渲染这种嵌套表格的建议。我猜这不是来自react-hook-form的问题,但是实现中有一个错误似乎导致了问题。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。