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

React Hook Form:如何在动态表单中管理每张卡片的独立控件?

问题解决:切换选中卡片时侧边栏设置无法更新

问题背景

开发表单构建页面时,布局为中间展示卡片列表,点击卡片后侧边栏加载对应卡片的配置项。但切换选中卡片时,侧边栏的设置会保留上一张卡片的配置,无法正确更新。尝试过register方法,每次侧边栏开关或切换都会重复注册;改用useController后问题依旧。

问题原因

切换选中卡片时,FocusCard组件的index属性变化,导致useController的name参数(survey.questions.${index}.checked)改变,但useController内部未自动响应该变化重新关联新字段,仍绑定旧字段值。同时组件重新渲染时未强制触发useController更新。

解决方案

给FocusCard组件添加唯一key,确保切换选中项时组件完全卸载重建,让useController重新初始化绑定新字段;此方案简单直接,能快速解决缓存问题。

修改后的代码

import React, { useState } from "react";
import { useForm, useFieldArray, useController } from "react-hook-form";

function FocusCard({ question, index, control }) {
  const { field } = useController({
    name: `survey.questions.${index}.checked`,
    control,
    defaultValue: false
  });
  return (
    <div>
      <div>{`Question: ${question.question}`}</div>
      <label>Check me</label>
      <input type="checkbox" {...field} />
    </div>
  );
}

function QuestionCard({ question, index, setFocus }) {
  return (
    <div className="question" onClick={(e) => setFocus(e, index)}>
      {question.question}
    </div>
  );
}

export default function App() {
  const [selectedIndex, setIndex] = useState(null);
  const { register, handleSubmit, control, getValues, setValue } = useForm({
    defaultValues: {
      survey: {
        question: "",
        questions: []
      }
    }
  });

  const { fields, append } = useFieldArray({
    control: control,
    name: "survey.questions"
  });

  const handleSave = (data) => {
    console.log(data);
  };

  const handleAddQuestion = (e) => {
    const newQuestion = getValues("survey.question");
    if (newQuestion.trim() !== "") {
      append({ question: newQuestion, checked: false });
      setValue("survey.question", "");
    }
  };

  const handleFocus = (e, index) => {
    setIndex(selectedIndex === index ? null : index);
  };

  return (
    <div className="App">
      <form onSubmit={handleSubmit(handleSave)}>
        <h2>Focused Question</h2>
        {selectedIndex !== null && (
          <FocusCard
            key={`focus-card-${selectedIndex}`}
            index={selectedIndex}
            control={control}
            question={fields[selectedIndex]}
          />
        )}
        <h2>All Questions</h2>
        {fields.map((q, i) => (
          <QuestionCard
            key={q.id}
            question={q}
            index={i}
            setFocus={handleFocus}
          />
        ))}
        <br />
        <input type="text" {...register("survey.question")} />
        <button type="button" onClick={handleAddQuestion}>
          Add Question
        </button>
        <button type="button" onClick={() => setIndex(null)}>Unfocus</button>
        <button type="submit">Print Data to Console</button>
      </form>
    </div>
  );
}

关键修改点

  • 给FocusCard组件添加key={focus-card-${selectedIndex}},切换选中项时强制组件卸载重建,让useController重新绑定新字段
  • 在useForm中显式设置defaultValues,确保表单初始状态稳定
  • 添加新问题时默认设置checked: false,避免字段缺失
  • 简化handleFocus逻辑写法

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 17:33:22