如何从Headless-UI Listbox组件获取值并存入表单状态
如何将封装后的Headless UI Listbox组件值同步到表单状态里
核心思路
把封装的Listbox组件改成受控组件,让它接收外部传入的value和onChange回调,将内部选中行为与父表单的状态联动,实现值的同步。
步骤1:修改封装的Listbox组件
移除组件内部的独立选中状态,改为从props接收value和onChange,并传递给Headless UI原生Listbox组件:
import { Fragment } from 'react' import { Listbox, Transition } from '@headlessui/react' import { CheckIcon, SelectorIcon } from '@heroicons/react/solid' // 将选项数据也改为props传入,提升组件复用性 export default function CustomListbox({ value, onChange, options }) { return ( <div className="fixed top-16 w-72"> {/* 传递父组件传入的value和onChange */} <Listbox value={value} onChange={onChange}> <div className="relative mt-1"> <Listbox.Button className="relative w-full cursor-default rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm"> <span className="block truncate">{value.name}</span> <span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2"> <SelectorIcon className="h-5 w-5 text-gray-400" aria-hidden="true" /> </span> </Listbox.Button> <Transition as={Fragment} leave="transition ease-in duration-100" leaveFrom="opacity-100" leaveTo="opacity-0" > <Listbox.Options className="absolute 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"> {options.map((person, personIdx) => ( <Listbox.Option key={personIdx} className={({ active }) => `relative cursor-default select-none py-2 pl-10 pr-4 ${active ? 'bg-amber-100 text-amber-900' : 'text-gray-900'}` } value={person} > {({ selected }) => ( <> <span className={`block truncate ${selected ? 'font-medium' : 'font-normal'}`} > {person.name} </span> {selected ? ( <span className="absolute inset-y-0 left-0 flex items-center pl-3 text-amber-600"> <CheckIcon className="h-5 w-5" aria-hidden="true" /> </span> ) : null} </> )} </Listbox.Option> ))} </Listbox.Options> </Transition> </div> </Listbox> </div> ) }
步骤2:在设置表单组件中使用封装的Listbox
在表单组件内维护自身状态,将状态值和更新函数传递给CustomListbox:
import { useState } from 'react' import CustomListbox from './CustomListbox' // 表单选项数据 const people = [ { name: 'Wade Cooper' }, { name: 'Arlene Mccoy' }, { name: 'Devon Webb' }, { name: 'Tom Cook' }, { name: 'Tanya Fox' }, { name: 'Hellen Schmidt' }, ] export default function SettingsForm() { // 维护表单全局状态 const [formState, setFormState] = useState({ selectedPerson: people[0] }) // 处理Listbox值变化,同步更新表单状态 const handlePersonChange = (selectedPerson) => { setFormState(prev => ({ ...prev, selectedPerson })) } return ( <form> {/* 其他表单字段... */} <CustomListbox value={formState.selectedPerson} onChange={handlePersonChange} options={people} /> {/* 提交按钮等表单元素... */} </form> ) }
关键说明
- 封装后的
CustomListbox不再管理内部选中状态,完全由父表单的formState控制,确保数据唯一来源。 - 用户在Listbox中选择新选项时,会触发父组件的
handlePersonChange函数,直接更新表单状态,完成值的同步。
内容的提问来源于stack exchange,提问作者hypercoded
相关产品推荐
相关产品推荐

