Next.js 13中基于React useFieldArray实现多组尺寸(width、height、length)输入字段堆叠的实现方法问询
Next.js 13中基于React useFieldArray实现多组尺寸(width、height、length)输入字段堆叠的实现方法问询
嗨,我正好做过类似的需求,给你详细说说在Next.js 13里用React Hook Form的useFieldArray实现动态多组尺寸输入的具体方案,完全匹配你想要的堆叠效果:
第一步:安装必要依赖
首先得确保项目里装了React Hook Form,毕竟useFieldArray是它的核心功能之一;如果需要做表单校验,还可以搭配Zod这类校验库一起用:
npm install react-hook-form @hookform/resolvers zod # 用yarn的话就执行下面这条 yarn add react-hook-form @hookform/resolvers zod
第二步:编写客户端组件(重点!)
Next.js 13的App Router默认是服务端组件,而表单交互需要客户端环境,所以一定要给组件加上'use client'指令。下面是完整的可运行示例代码:
'use client'; import { useForm, useFieldArray, Controller } from 'react-hook-form'; import { z } from 'zod'; import { zodResolver } from '@hookform/resolvers/zod'; // 定义单组尺寸的校验规则 const SizeItemSchema = z.object({ width: z.number().positive('宽度必须是正数'), height: z.number().positive('高度必须是正数'), length: z.number().positive('长度必须是正数'), }); // 定义整个表单的校验规则 const FormSchema = z.object({ sizes: z.array(SizeItemSchema).min(1, '至少需要填写一组尺寸'), }); // 推导表单值的类型 type FormValues = z.infer<typeof FormSchema>; export default function MultiSizeForm() { // 初始化表单,绑定校验规则和默认值 const { control, handleSubmit, formState: { errors } } = useForm<FormValues>({ resolver: zodResolver(FormSchema), defaultValues: { sizes: [{ width: 0, height: 0, length: 0 }], // 初始化一组默认尺寸,确保页面加载后有输入框 }, }); // 初始化useFieldArray,绑定表单控制器和数组字段名 const { fields, append, remove } = useFieldArray({ control, name: 'sizes', }); // 表单提交逻辑 const onSubmit = (data: FormValues) => { console.log('提交的所有尺寸数据:', data.sizes); // 这里可以写你的业务逻辑,比如调用API提交数据 }; return ( <form onSubmit={handleSubmit(onSubmit)} className="space-y-6 p-8 max-w-3xl mx-auto"> <h2 className="text-xl font-bold mb-4">多组尺寸设置</h2> {/* 循环渲染每一组尺寸输入框 */} {fields.map((field, index) => ( <div key={field.id} className="flex gap-4 items-center p-4 border rounded-lg bg-gray-50"> {/* 宽度输入框 */} <div className="flex-1"> <label className="block text-sm font-medium mb-1">宽度</label> <Controller name={`sizes.${index}.width`} control={control} render={({ field }) => ( <input type="number" {...field} value={field.value || ''} className="w-full border rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" /> )} /> {/* 校验错误提示 */} {errors.sizes?.[index]?.width && ( <p className="text-red-500 text-xs mt-1">{errors.sizes[index].width.message}</p> )} </div> {/* 高度输入框 */} <div className="flex-1"> <label className="block text-sm font-medium mb-1">高度</label> <Controller name={`sizes.${index}.height`} control={control} render={({ field }) => ( <input type="number" {...field} value={field.value || ''} className="w-full border rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" /> )} /> {errors.sizes?.[index]?.height && ( <p className="text-red-500 text-xs mt-1">{errors.sizes[index].height.message}</p> )} </div> {/* 长度输入框 */} <div className="flex-1"> <label className="block text-sm font-medium mb-1">长度</label> <Controller name={`sizes.${index}.length`} control={control} render={({ field }) => ( <input type="number" {...field} value={field.value || ''} className="w-full border rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" /> )} /> {errors.sizes?.[index]?.length && ( <p className="text-red-500 text-xs mt-1">{errors.sizes[index].length.message}</p> )} </div> {/* 删除按钮:只有当组数大于1时才显示 */} {fields.length > 1 && ( <button type="button" onClick={() => remove(index)} className="text-red-500 hover:text-red-700 transition-colors" > 删除 </button> )} </div> ))} {/* 添加新组按钮 */} <button type="button" onClick={() => append({ width: 0, height: 0, length: 0 })} className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors" > 添加一组尺寸 </button> {/* 提交按钮 */} <button type="submit" className="px-6 py-2 bg-green-500 text-white rounded hover:bg-green-600 transition-colors" > 提交表单 </button> </form> ); }
第三步:关键细节说明
'use client'指令:在Next.js 13 App Router中必须添加,否则客户端交互相关的API会报错;如果用的是Pages Router,不需要加这行useFieldArray核心方法:fields:存储当前所有的尺寸组数据,用来循环渲染输入框append:添加新的一组尺寸数据remove:删除指定索引的尺寸组
- Controller组件:搭配Zod校验时,用
Controller能更顺畅地实现受控组件和表单状态的同步,同时处理校验逻辑 - 样式调整:示例用了Tailwind样式,你可以根据自己项目的UI库(比如MUI、Ant Design)修改样式,实现和你GIF里一样的堆叠视觉效果
备注:内容来源于stack exchange,提问作者Amith A G
相关产品推荐
相关产品推荐

