Next.js14+Supabase下拉框值无法传递至Server Action问题
解决Next.js 14中自定义下拉框值无法传递到Server Action的问题
问题原因
你使用的Headless UI Listbox是纯UI交互组件,本身不会自动生成表单提交所需的表单控件(如<input>或<select>),因此选中的barangay值不会被包含在表单提交的FormData中,导致Server Action无法接收该字段。
解决方案
在自定义DropdownList组件内部添加一个隐藏的input元素,将选中的值绑定到该input的value属性,并设置对应的name属性,这样表单提交时就会自动携带该字段的值。
修改后的DropdownList.tsx代码
import React, { Fragment, useState, useEffect } from 'react'; import { Listbox, Transition } from '@headlessui/react'; import { CheckIcon, ChevronUpDownIcon } from '@heroicons/react/20/solid'; type Props = { options: string[]; selected: string; onSelect: (value: string) => void; required: boolean; placeholder: string; value: string; name: string; }; function classNames(...classes: string[]) { return classes.filter(Boolean).join(' '); } const DropdownList: React.FC<Props> = ({ options, selected, onSelect, required, placeholder, value, name }) => { const [currentSelected, setCurrentSelected] = useState<string | null>(selected); useEffect(() => { setCurrentSelected(selected); }, [selected]); return ( <Listbox value={currentSelected} onChange={(value) => { if (value !== null) { setCurrentSelected(value); onSelect(value); } }}> {({ open }) => ( <> <Listbox.Label className="block text-sm font-medium leading-6 text-gray-900"> Select an option </Listbox.Label> {/* 添加隐藏input,用于表单提交 */} <input type="hidden" name={name} value={currentSelected || ''} required={required} /> <div className="relative mt-2"> <Listbox.Button className={`relative w-full cursor-default rounded-md bg-white py-1.5 pl-3 pr-10 text-left text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:outline-none focus:ring-2 focus-ring-indigo-500 sm:text-sm sm:leading-6 ${required ? 'required' : ''}`}> <span className="ml-3 block truncate">{currentSelected || placeholder}</span> <span className="pointer-events-none absolute inset-y-0 right-0 ml-3 flex items-center pr-2"> <ChevronUpDownIcon className="h-5 w-5 text-gray-400" aria-hidden="true" /> </span> </Listbox.Button> <Transition show={open} as={Fragment} leave="transition ease-in duration-100" leaveFrom="opacity-100" leaveTo="opacity-0" > <Listbox.Options className="absolute z-10 mt-1 max-h-56 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"> <Listbox.Option key="placeholder" value="" disabled> {({ active }) => ( <span className={classNames('text-gray-500', 'ml-3 block truncate')}> {placeholder} </span> )} </Listbox.Option> {options.map((option, i) => ( <Listbox.Option key={i} className={({ active }) => classNames( active ? 'bg-indigo-600 text-white' : 'text-gray-900', 'relative cursor-default select-none py-2 pl-3 pr-9' ) } value={option} > {({ selected, active }) => ( <> <span className={classNames(selected ? 'font-semibold' : 'font-normal', 'ml-3 block truncate')}> {option} </span> {selected ? ( <span className={classNames( active ? 'text-white' : 'text-indigo-600', 'absolute inset-y-0 right-0 flex items-center pr-4' )} > <CheckIcon className="h-5 w-5" aria-hidden="true" /> </span> ) : null} </> )} </Listbox.Option> ))} </Listbox.Options> </Transition> </div> </> )} </Listbox> ); }; export default DropdownList;
关键修改点
- 在
Listbox内部添加了<input type="hidden" />元素,将name设置为组件接收的props.name(即"barangay"),value绑定到当前选中的值currentSelected。 - 同步设置了
required属性,确保表单验证生效。
验证修改效果
修改后重新提交表单,Server Action中的FormData应该会包含barangay字段及其选中的值,此时你可以通过formData.get('barangay')获取该值并插入到Supabase数据库中。
内容的提问来源于stack exchange,提问作者JS3
相关产品推荐
相关产品推荐

