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

如何将react-hook-form的register与Headless UI Combobox配合使用

解决Headless UI Combobox与react-hook-form(register方式)集成的报错问题

问题分析

你遇到的Cannot read properties of undefined (reading 'name')错误主要来自两个原因:

  1. 直接将react-hook-form的register方法挂载到Headless UI的Combobox组件上无效——Combobox并非原生表单控件,register无法处理其值变化逻辑。
  2. 当输入的查询文本无匹配选项时,Combobox的value可能变为undefined,此时displayValue尝试访问person.name会触发空值报错。

解决方案代码

import React, { useState } from "react";
import { Combobox } from "@headlessui/react";
import { useForm } from "react-hook-form";

const people = [
  { id: 1, name: "Durward Reynolds" },
  { id: 2, name: "Kenton Towne" },
  { id: 3, name: "Therese Wunsch" },
  { id: 4, name: "Benedict Kessler" },
  { id: 5, name: "Katelyn Rohan" },
];

function Example() {
  const [query, setQuery] = useState("");
  const { register, handleSubmit, setValue, watch, formState: { errors } } = useForm({
    defaultValues: { assignee: people[0] }
  });

  const selectedPerson = watch("assignee");

  const filteredPeople = query === ""
    ? people
    : people.filter(person => 
        person.name.toLowerCase().includes(query.toLowerCase())
      );

  const submit = (data) => {
    console.log(JSON.stringify(data));
  };

  return (
    <form onSubmit={handleSubmit(submit)}>
      <Combobox
        as="div"
        value={selectedPerson}
        onChange={(person) => {
          setValue("assignee", person);
          setQuery(person?.name || "");
        }}
      >
        <Combobox.Input
          onChange={(event) => {
            const inputValue = event.target.value;
            setQuery(inputValue);
            const matchedPerson = people.find(person => 
              person.name.toLowerCase() === inputValue.toLowerCase()
            );
            setValue("assignee", matchedPerson || undefined);
          }}
          displayValue={(person) => person?.name || ""}
        />
        <Combobox.Options>
          {filteredPeople.map((person) => (
            <Combobox.Option key={person.id} value={person}>
              {person.name}
            </Combobox.Option>
          ))}
        </Combobox.Options>
      </Combobox>
      {errors.assignee && <p style={{ color: "red" }}>请选择一个联系人</p>}
      <button type="submit">提交</button>
    </form>
  );
}

export default function Check() {
  return (
    <div>
      <Example />
    </div>
  );
}

关键改动说明

  1. 表单默认值配置:将原Combobox的defaultValue移至useForm的defaultValues中,确保表单初始状态与组件同步。
  2. 状态同步:用watch("assignee")获取表单当前选中值,作为Combobox的value,双向绑定组件与表单状态。
  3. 手动更新表单值:移除Combobox上的register,改为在Combobox的onChange事件中调用setValue更新表单值,同时同步输入框的查询文本。
  4. 输入逻辑处理:在Combobox.Input的onChange中,检查输入文本是否匹配选项,匹配则自动选中对应项,否则将表单值设为undefined。
  5. 空值防护:修改displayValue为person?.name || "",用可选链操作符避免空值访问报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 14:35:38