跳到主要内容

复杂表单设计与优化

场景

需要实现一个包含动态字段、联动校验、分步填写的复杂表单(如注册流程、保险投保表单),该怎么设计?

方案设计

核心挑战

挑战说明
联动校验字段 A 的值影响字段 B 的可选项/校验规则
动态字段字段数量不固定,可增删
分步表单多步骤填写,步骤间共享数据
性能字段很多时输入不能卡顿

Schema 驱动表单

表单 Schema 定义
interface FormField {
name: string;
label: string;
type: 'text' | 'select' | 'number' | 'date';
required?: boolean;
rules?: ValidationRule[];
options?: Array<{ label: string; value: string }>;
dependsOn?: {
field: string;
condition: (value: unknown) => boolean;
};
}

const formSchema: FormField[] = [
{ name: 'type', label: '类型', type: 'select', required: true, options: [
{ label: '个人', value: 'personal' },
{ label: '企业', value: 'company' },
]},
{ name: 'companyName', label: '公司名', type: 'text', dependsOn: {
field: 'type',
condition: (v) => v === 'company', // 只在选择"企业"时显示
}},
];

性能优化

✅ 隔离重渲染
// 使用 React Hook Form 避免整个表单重渲染
import { useForm, Controller } from 'react-hook-form';

function ComplexForm() {
const { control, handleSubmit } = useForm({
defaultValues: { name: '', email: '' },
});

return (
<form onSubmit={handleSubmit(onSubmit)}>
{/* 每个 Controller 独立渲染,不会因为其他字段变化而重渲染 */}
<Controller
name="name"
control={control}
rules={{ required: '请输入姓名' }}
render={({ field, fieldState }) => (
<div>
<input {...field} />
{fieldState.error && <span>{fieldState.error.message}</span>}
</div>
)}
/>
</form>
);
}
✅ 分步表单数据共享
function MultiStepForm() {
const [step, setStep] = useState(1);
const [formData, setFormData] = useState<Partial<FormData>>({});

const updateData = (data: Partial<FormData>) => {
setFormData((prev) => ({ ...prev, ...data }));
};

switch (step) {
case 1: return <Step1 data={formData} onNext={(d) => { updateData(d); setStep(2); }} />;
case 2: return <Step2 data={formData} onNext={(d) => { updateData(d); setStep(3); }} onBack={() => setStep(1)} />;
case 3: return <Step3 data={formData} onSubmit={(d) => { updateData(d); submitForm({ ...formData, ...d }); }} />;
}
}

常见面试问题

Q1: 大表单输入卡顿怎么优化?

答案

  1. 使用 React Hook Formformily,避免每个输入触发整个表单重渲染
  2. 对长列表字段使用虚拟列表
  3. 校验使用 debounce,不要每次输入都校验
  4. 复杂联动逻辑用 useMemo 缓存

相关链接