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

ReactHookForm+ReactQuery+Zod隐藏默认值赋值及表单提交问题排查

问题解决:React Hook Form + React Query 表单关联用户失败&重复渲染问题

核心问题诊断

  1. 提交无响应:Zod校验失败导致表单无法提交。你在fetchUser里用profileFormSchema.parse({ id: res.data.data }),但Schema定义的字段是user_id,且类型为string|null,但返回的res.data.data是number类型,解析失败后表单处于错误状态,直接阻止了提交动作。
  2. 重复打印id/重复渲染:React Query因fetchUser中的Zod解析错误触发重试机制,导致接口反复调用,id重复打印;同时隐藏字段的错误写法引发组件不必要的重复渲染。
  3. 隐藏字段传递错误:手动给hidden input设置value={data.user_id}会覆盖React Hook Form的字段控制逻辑,导致表单状态混乱,进一步影响提交逻辑。

修正步骤

1. 修复用户数据获取与解析

修改fetchUser函数,返回符合Schema结构的数据,并转换id类型:

async function fetchUser() {
  const res = await axios.get('/api/get-user');
  const userId = res.data.data;
  console.log('id:', userId);
  // 转换为string类型,匹配user_id的schema定义
  return { user_id: userId?.toString() || null };
}

2. 正确关联用户ID到表单

方式一:用React Hook Form的setValue设置(推荐)

不需要隐藏字段,在React Query获取到用户数据后,直接设置表单字段:

const { data: userData } = useQuery({
  queryKey: ['current-user'],
  queryFn: fetchUser,
  retry: 1, // 限制重试次数,避免接口反复调用
});

// 用户数据加载完成后同步到表单
useEffect(() => {
  if (userData?.user_id) {
    form.setValue('user_id', userData.user_id);
  }
}, [userData, form]);

方式二:修正隐藏字段写法(不推荐)

如果坚持使用隐藏字段,不要手动覆盖value,让React Hook Form完全控制字段:

// 初始化表单时传入user_id默认值
const form = useForm<ProfileFormValues>({
  resolver: zodResolver(profileFormSchema),
  defaultValues: {
    ...defaultValues,
    user_id: userData?.user_id || null,
  },
  mode: 'onChange',
});

// 隐藏字段仅绑定field,无需手动设置value
<FormField
  name='user_id'
  control={form.control}
  render={({ field }) => (
    <input type='hidden' {...field} />
  )}
/>

3. 更安全的提交逻辑(最优方案)

完全不在表单中维护user_id字段,提交时直接将用户ID加入请求体,避免前端暴露或篡改风险:

// 修改Zod Schema,移除user_id字段(不再作为表单输入项)
const profileFormSchema = z.object({
  email: z.string().min(2).max(320).email(),
  title: z.string({ required_error: 'Please provide a title for your e-mail.' }),
  content: z.string().max(10000).min(4),
  can_share: z.boolean(),
});

type ProfileFormValues = z.infer<typeof profileFormSchema>;

// 提交时合并用户ID
async function onSubmit(formData: ProfileFormValues) {
  const submitData = {
    ...formData,
    user_id: userData?.user_id || null,
  };
  
  const res = await fetch('/api/create', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(submitData),
  });
  
  const json = await res.json();
  if (json.status === 201) {
    toast.success('Template created!');
    setUrl(json.data);
  }
}

额外优化点

  • 给React Query设置retry:1,避免接口错误时反复调用。
  • 实现未登录跳转逻辑:
const { data: userData, isError } = useQuery({
  queryKey: ['current-user'],
  queryFn: fetchUser,
  retry: 1,
});

if (isError || !userData?.user_id) {
  redirect('/login');
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 12:52:44