如何在Headless UI的Combobox中设置默认选中项?
如何让Headless UI Combobox默认选中第一个选项
Headless UI的Combobox是受控组件,选中状态完全由value属性控制,defaultValue仅适用于非受控场景,所以你之前用defaultValue无效是因为组件处于受控模式。要实现默认选中第一个选项,只需确保value绑定的状态初始值为第一个选项即可,具体有两种方案:
方案1:在父组件初始化状态
你的FormCombobox组件依赖父组件传入的questionRange和setQuestionRange,所以最直接的方式是在父组件中把questionRange的初始值设为数据源转换后的第一个选项:
// 父组件示例代码 import { useState } from 'react'; import FormCombobox from './FormCombobox'; function ParentComponent() { // 假设这是你的数据源 const comboboxData = [/* 你的数据项 */]; // 初始化选中第一个选项 const [questionRange, setQuestionRange] = useState( comboboxData.length > 0 ? { id: comboboxData[0].content_object.nanoid, name: comboboxData[0].content_object.name, multiplier: comboboxData[0].multiplier, } : null ); return ( <FormCombobox comboboxData={comboboxData} label="选择范围" questionRange={questionRange} setQuestionRange={setQuestionRange} /> ); }
方案2:在子组件内部处理默认值
如果父组件没有传递初始值,也可以在FormCombobox组件内部自动设置默认选中项,通过useEffect同步到父组件状态:
import { useState, useEffect } from 'react' import { CheckIcon, ChevronUpDownIcon } from '@heroicons/react/20/solid' import { Combobox } from '@headlessui/react' function classNames(...classes) { return classes.filter(Boolean).join(' ') } export default function FormCombobox({ comboboxData, label, questionRange, setQuestionRange, }) { const [query, setQuery] = useState('') let items = comboboxData.map((item) => ({ id: item.content_object.nanoid, name: item.content_object.name, multiplier: item.multiplier, })) // 组件加载时,自动选中第一个选项(如果当前没有选中项) useEffect(() => { if (!questionRange && items.length > 0) { setQuestionRange(items[0]) } }, [questionRange, items, setQuestionRange]) const filteredItems = query === '' ? items : items.filter((item) => { return item.name.toLowerCase().includes(query.toLowerCase()) }) // 确保选中值不为空,无选项时设为null const currentValue = questionRange ?? (items.length > 0 ? items[0] : null) return ( <Combobox as="div" value={currentValue} onChange={setQuestionRange} className="my-5" > <Combobox.Label className="block text-left font-bold text-gray-700"> {label} </Combobox.Label> <div className="relative mt-1"> <Combobox.Input className="w-full rounded-md border border-gray-300 bg-white py-2 pl-3 pr-10 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 sm:text-sm" onChange={(event) => setQuery(event.target.value)} displayValue={(item) => item?.name} /> <Combobox.Button className="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none"> <ChevronUpDownIcon className="h-5 w-5 text-gray-400" aria-hidden="true" /> </Combobox.Button> {filteredItems.length > 0 && ( <Combobox.Options className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"> {filteredItems.map((item) => ( <Combobox.Option key={item.id} value={item} className={({ active }) => classNames( 'relative cursor-default select-none py-2 pl-3 pr-9', active ? 'bg-indigo-600 text-white' : 'text-gray-900' ) } > {({ active, selected }) => ( <> <span className={classNames( 'block truncate', selected && 'font-semibold' )} > {item.name} </span> {selected && ( <span className={classNames( 'absolute inset-y-0 right-0 flex items-center pr-4', active ? 'text-white' : 'text-indigo-600' )} > <CheckIcon className="h-5 w-5" aria-hidden="true" /> </span> )} </> )} </Combobox.Option> ))} </Combobox.Options> )} </div> </Combobox> ) }
关键注意点
- 必须确保
value绑定的是完整的选项对象(和Combobox.Option的value结构一致),不能是字符串或其他类型,否则组件无法识别选中状态。 - 受控模式下
defaultValue会被value覆盖,所以直接设置value的初始值是唯一有效的方式。
内容的提问来源于stack exchange,提问作者Enes
相关产品推荐
相关产品推荐

