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

使用react-hook-form的useController结合Tabs时状态异常问题

问题分析与修复方案

核心问题

  1. 表单提交逻辑错误:onSubmit写法不正确,未正确调用react-hook-form的提交处理函数
  2. Tab与表单字段命名不匹配:Tab名称(tab1/tab2)和初始状态的键(step1/step2)不一致,导致useController无法关联对应字段
  3. Feature组件取值错误:useController获取的value已经是当前Tab对应的子对象(如step1的{statement, weight, statements}),但错误尝试访问value.tab1?.statement,应直接访问value.statement

修正后的代码

1. 表单主组件修正

const initialValues = {
  step1: {
    statement: '',
    weight: '',
    statements: [],
  },
  step2: {
    statement: '',
    weight: '',
    statements: [],
  },
  step3: {
    statement: '',
    weight: '',
    statements: [],
  },
};

const Form = () => {
  const methods = useForm({ defaultValues: initialValues });
  // 正确绑定提交处理函数
  const onSubmit = methods.handleSubmit((data) => {
    console.log('data: ', data);
  });

  return (
    <form onSubmit={onSubmit}>
      <FormProvider {...methods}>
        <section>
          <TabContent
            // 用initialValues的键作为Tab列表,保证命名一致
            tabsList={Object.keys(initialValues)}
            defaultTab="step1"
          >
            {(activeTab) => {
              console.log('rendering for: ', activeTab);
              return <Feature tabName={activeTab} />;
            }}
          </TabContent>
          {/* 添加提交按钮触发表单提交 */}
          <button type="submit">提交</button>
        </section>
      </FormProvider>
    </form>
  );
};

export default Form;

2. Feature组件修正

import React, { memo, useEffect } from 'react';
import { useController } from 'react-hook-form';

const Feature = ({ tabName }) => {
  console.log('rendering tab', tabName);
  // useController关联对应step的字段
  const {
    field: { value, onChange: fieldOnChange },
  } = useController({ name: tabName });

  const onChangeStatement = (e) =>
    fieldOnChange({
      ...value,
      statement: e.target.value,
    });

  const onChangeWeight = (e) =>
    fieldOnChange({
      ...value,
      weight: e.target.value,
    });

  useEffect(() => {
    console.log('tabName: ', tabName);
    console.log('value: ', value);
  }, [tabName, value]);

  return (
    <>
      <h1>{tabName}</h1>
      {/* 直接使用当前Tab对应对象的属性 */}
      <input 
        onChange={onChangeStatement} 
        value={value.statement} 
        placeholder="输入声明"
      />
      <input 
        onChange={onChangeWeight} 
        value={value.weight} 
        placeholder="输入权重"
      />
    </>
  );
};

export default memo(Feature);

额外说明

如果你的Tab组件必须使用tab1/tab2作为名称,可在Feature组件中添加映射关系:

const tabToStepMap = {
  tab1: 'step1',
  tab2: 'step2',
  tab3: 'step3'
};
// 关联对应字段
const { field } = useController({ name: tabToStepMap[tabName] });

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 17:23:20