多步表单字段唯一性校验时JSON格式错误排查与优化咨询
问题解决与优化建议
核心错误修复
1. 修正API请求体格式
后端期望从req.body.carnet获取值,但当前API客户端直接将字符串carnet转为JSON(比如输入"xValue"会变成"\"xValue\""),导致后端JSON解析失败。修改API客户端代码,将请求体改为对象格式:
export const checkCarnet = async (carnet: string): Promise<RevisarDato> => { console.log(carnet); const response = await fetch(`${BASE_API_URL}/api/auth/check-carnet`, { method: "POST", // 改为传递包含carnet字段的对象 body: JSON.stringify({ carnet }), headers: { "Content-type": "application/json", }, }); if (!response.ok) { throw new Error("Something went wrong"); } const returnData = await response.json(); return returnData; };
2. 移除冗余状态管理(推荐)
同时使用react-hook-form的register和自定义useState维护输入值,容易导致状态不一致。可以用react-hook-form的watch方法直接获取实时输入值,省去单独的useState:
import { useForm, watch } from "react-hook-form"; // 组件内逻辑 const { register, watch } = useForm(); const carnetValue = watch("carnet"); // React Query直接使用watch到的值 const { data: isUnique } = useQuery(["checkCarnet", carnetValue], () => apiClient.checkCarnet(carnetValue), { enabled: !!carnetValue }); // 输入框无需自定义onChange <input type="text" className="border border-blue-500 w-full py-1 px-2 font-normal" {...register("carnet", { required: "Este campo es necesario" })} />
代码反馈
统一后端返回格式:当前成功返回
{message: true}、失败返回{result: false},格式不一致建议统一:// 成功 return res.status(200).json({ isUnique: true }); // 失败 return res.status(400).json({ isUnique: false });前端处理时无需判断不同字段名,逻辑更简洁。
优化数据库查询:仅需判断记录是否存在,无需查询所有字段,用
SELECT 1代替SELECT *提升性能:const yaExiste = await pool.query( "SELECT 1 FROM Personas WHERE carnet = $1", [carnet] );增强后端错误处理:添加JSON解析错误捕获,避免服务器崩溃,同时处理空值输入:
export const checkCarnet = async (req: Request, res: Response) => { try { const { carnet } = req.body; if (!carnet) { return res.status(400).json({ isUnique: false, error: "Carnet不能为空" }); } const yaExiste = await pool.query( "SELECT 1 FROM Personas WHERE carnet = $1", [carnet] ); return res.status(200).json({ isUnique: yaExiste.rows.length === 0 }); } catch (error) { if (error instanceof SyntaxError) { return res.status(400).json({ error: "请求格式错误" }); } console.log(error); res.status(500).json({ error: "Internal Server Error 500" }); } };
表单唯一性校验优化建议
添加防抖处理:避免用户每输入一个字符就发起API请求,减少服务器压力。可使用
useDebounce:import { useDebounce } from "@react-hook/debounce"; const debouncedCarnet = useDebounce(carnetValue, 500); // 500ms防抖 const { data: isUnique } = useQuery(["checkCarnet", debouncedCarnet], () => apiClient.checkCarnet(debouncedCarnet), { enabled: !!debouncedCarnet });整合到react-hook-form校验规则:将唯一性校验作为自定义规则,错误信息直接绑定到表单字段:
const { register, formState: { errors } } = useForm(); const checkCarnetUnique = async (value: string) => { if (!value) return true; const result = await apiClient.checkCarnet(value); return result.isUnique || "该Carnet已存在"; }; // 输入框注册时添加自定义校验 <input type="text" className="border border-blue-500 w-full py-1 px-2 font-normal" {...register("carnet", { required: "Este campo es necesario", validate: checkCarnetUnique })} /> {/* 显示错误信息 */} {errors.carnet && <p className="text-red-500">{errors.carnet.message}</p>}多步表单状态管理:使用react-hook-form的
useFormContext在多步表单之间共享状态,避免各步骤单独维护数据,同时可在最后一步统一提交前做完整校验。
内容的提问来源于stack exchange,提问作者yzkael
相关产品推荐
相关产品推荐

