You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多步表单字段唯一性校验时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" })}
/>

代码反馈

  1. 统一后端返回格式:当前成功返回{message: true}、失败返回{result: false},格式不一致建议统一:

    // 成功
    return res.status(200).json({ isUnique: true });
    // 失败
    return res.status(400).json({ isUnique: false });
    

    前端处理时无需判断不同字段名,逻辑更简洁。

  2. 优化数据库查询:仅需判断记录是否存在,无需查询所有字段,用SELECT 1代替SELECT *提升性能:

    const yaExiste = await pool.query(
      "SELECT 1 FROM Personas WHERE carnet = $1",
      [carnet]
    );
    
  3. 增强后端错误处理:添加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" });
      }
    };
    

表单唯一性校验优化建议

  1. 添加防抖处理:避免用户每输入一个字符就发起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
    });
    
  2. 整合到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>}
    
  3. 多步表单状态管理:使用react-hook-form的useFormContext在多步表单之间共享状态,避免各步骤单独维护数据,同时可在最后一步统一提交前做完整校验。

内容的提问来源于stack exchange,提问作者yzkael

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 05:05:03