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

将Formik表单重构为react-hook-form v7:实现实时输入监听与组件表单值访问

重构Formik表单到react-hook-form v7 解决方案

1. 基础表单结构改造

替换Formik的上下文与表单容器为react-hook-form的对应实现,同时初始化表单方法:

import { useForm, FormProvider } from "react-hook-form";

const YourFormComponent = () => {
  const formMethods = useForm({
    defaultValues: {
      fighterInput: "" // 与目标字段名保持一致
    }
  });

  const yourSubmitHandler = (data) => {
    // 处理表单提交逻辑
    console.log(data);
  };

  return (
    <FormProvider {...formMethods}>
      <form onSubmit={formMethods.handleSubmit(yourSubmitHandler)}>
        <FighterInput fighterAvailability={fighterAvailabilityStatus} />
        <StandardButton type="submit">提交</StandardButton>
      </form>
    </FormProvider>
  );
};

2. 正确用Controller集成FighterInput

你之前的写法错误在于同时混用了Controller和register(二者二选一即可),且字段名不统一。以下是正确的集成方式:

父组件中配置Controller

import { Controller } from "react-hook-form";

// 替换上述组件中FighterInput的位置
<Controller
  control={formMethods.control}
  name="fighterInput" // 与defaultValues中的字段名匹配
  render={({ field: { onChange, onBlur, value, ref } }) => (
    <FighterInput
      fighterAvailability={fighterAvailabilityStatus}
      onChange={onChange}
      onBlur={onBlur}
      value={value}
      inputRef={ref}
    />
  )}
/>

改造FighterInput组件

确保组件内部的输入框正确接收并使用传递来的props:

const FighterInput = ({ fighterAvailability, onChange, onBlur, value, inputRef }) => {
  // 保留原有的选手状态渲染逻辑
  return (
    <div>
      <input
        ref={inputRef}
        value={value}
        onChange={onChange} // 自动同步输入值到react-hook-form
        onBlur={onBlur}
        placeholder="输入选手信息"
      />
      {fighterAvailability === "available" && (
        <div>该选手当前可用</div>
      )}
      {/* 其他原有业务逻辑 */}
    </div>
  );
};

3. 实时获取输入值触发useEffect

通过watch方法监听字段值变化,即可实时捕获每一次输入字符:

在父组件中监听

const YourFormComponent = () => {
  const formMethods = useForm({...});
  const fighterInputValue = formMethods.watch("fighterInput");

  useEffect(() => {
    // 每次输入变化都会触发此逻辑
    console.log("实时输入值:", fighterInputValue);
    // 调用你的其他业务函数
  }, [fighterInputValue]);

  // ... 其余代码
};

在FighterInput组件内监听

如果需要在组件内部处理实时输入逻辑,可使用useWatch钩子(需确保组件在FormProvider上下文范围内):

import { useWatch } from "react-hook-form";

const FighterInput = ({ fighterAvailability }) => {
  const fighterInputValue = useWatch({ name: "fighterInput" });

  useEffect(() => {
    // 在这里处理实时输入的业务逻辑
  }, [fighterInputValue]);

  // ... 其余组件逻辑
};

4. FighterInput访问表单值:useFormContext与FormProvider的配合

  • FormProvider:作为上下文容器,在表单最外层包裹,将formMethods传递给所有子组件,是子组件获取表单方法的前提。
  • useFormContext:在FighterInput内部调用,用于获取FormProvider提供的表单方法(如watch、getValues等),无需逐层传递props。

示例:在FighterInput中获取其他表单字段值

import { useFormContext } from "react-hook-form";

const FighterInput = ({ fighterAvailability }) => {
  const { getValues, watch } = useFormContext();
  
  // 获取单个字段的当前值
  const otherFieldValue = getValues("otherFieldName");
  // 实时监听其他字段的变化
  const watchedOtherField = watch("otherFieldName");

  // ... 组件逻辑
};

常见错误修正

  • 不要在Controller内部使用register,二者功能重叠,选其一即可。
  • 确保Controller的name属性与defaultValues中的字段名完全一致,否则无法正确同步值。
  • 使用useWatch时,组件必须处于FormProvider的上下文范围内,否则会报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 09:40:31