next.js 在组件上可以看到select的值,但是当将其传递给服务器操作时,它不再显示

7xzttuei  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(96)

我用的是Nextjs14和Supplement。
我有这个select,用户可以从中选择。我还将它传递给formValue,它将在服务器操作上作为FormData接收。现在,在组件上,我可以看到formValue的数据和barangay字段。然而,在服务器操作上传递,该barangay字段不再可以在服务器上看到的动作.
这是我的可重用组件,名为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}) => {
  // Initialize the selected state with the default selected value from the parent
  const [currentSelected, setCurrentSelected] = useState<string | null>(selected);

  // Update the selected state when the selected prop changes
  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>
          <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">
                {/* Add a placeholder option */}
                <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;

字符串

**我在这个表单上使用它:**在这个部分,我可以看到值barangay

'use client'
import addWaterStation from "@/app/auth/actions/WaterStation/addWaterStation";
import React, { useEffect, useState} from "react";
import { useFormState, useFormStatus } from "react-dom";
import DropdownList from "@/components/Reusables/MyDropDownList";
import { barangay } from "./barangay";

interface FormData {
  ...rest of the values
  barangay: string; 
}

const initialState = {
  message: null,
}

function SubmitButton() {
  const { pending } = useFormStatus()

  return (
    <button type="submit" aria-disabled={pending}>
      Submit
    </button>
  )
}

export default function WaterStationProfileForm() {
  const [state, formAction] = useFormState(addWaterStation, initialState)
  const [selectedBarangay, setSelectedBarangay] = useState<string>(''); // Rename the state variable

  const handleBarangaySelection = (value: string) => {
    setSelectedBarangay(value); //get the selected barangay
  }

  const [formValue, setFormValue] = useState<FormData>({
    ...rest of the values
    barangay: "",
  });
 

  useEffect(() => {
    setFormValue(prevFormValue => ({
      ...prevFormValue,
      barangay: selectedBarangay
    }))
  },[selectedBarangay])

  console.log(formValue, "form value") // I can see the value of barangay here

  return (
    <div className="container mx-auto p-4">

    <form action={formAction}>
      ...the rest of the inputs
      <DropdownList
        options={barangay}
        value={formValue.barangay} 
        selected={selectedBarangay} 
        onSelect={handleBarangaySelection}
        required={true}
        placeholder="Please select an option"
        name="barangay"
      />
      <SubmitButton />
    </form>
    </div>
  );
}

**我的服务器操作:**在此部分,值barangay不再存在。只有其余的值显示。示例FormData值。barangay不在name上并且没有值:

FormData {
  [Symbol(state)]: [
    { name: '$ACTION_REF_1', value: '' },
    {
      name: '$ACTION_1:0',
      value: '{"id":"32933f3a25fdc884c208dbcbf3540cf9ccf38c62","bound":"$@1"}'
    },
    { name: '$ACTION_1:1', value: '[{"message":null}]' },
    { name: '$ACTION_KEY', value: 'k3775125042' },
    { name: 'zone', value: '7' },
    { name: 'delivery_mode', value: 'Delivery and Pickup' },
    { name: 'contact_no', value: '9676832484' },
    { name: 'tel_no', value: '' },
    { name: 'remarks', value: '' }

  ]
} formData

服务端动作编码:

'use server'

import { createServerComponentClient } from "@supabase/auth-helpers-nextjs"
import { revalidatePath } from "next/cache";
import { cookies } from "next/headers"

export default async function addWaterStation(prevState: any, formData: FormData): Promise<{ message: string }> {    const supabase =createServerComponentClient({cookies})
    const {data: {user}} = await supabase.auth.getUser();
    const formDataAddress = `${formData.get('buildingNumber')}, ${formData.get('street')}, ${formData.get('zone')}`
    console.log(formData, "formData")

    try{
        const station_name = formData.get('name')

        const {data, error} = await supabase.from('water_refilling_station')
            .insert({
                ...rest of the inputs here
                barangay,
            }).select()
        
        if(error){
            return {message: `${error.message}  - unable to save`}
        } 

        revalidatePath('/water_station')
        return { message: `Succesfully added the data` }
    }catch(e){
        return {message: "Failed to submit the form."}
    }

}

k97glaaz

k97glaaz1#

<form>中放置一个隐藏的输入,只有输入值被传递给表单操作。
你可以用两种方法来解决这个问题,要么在你的下拉列表旁边呈现这个:

<input type="hidden" name="barangay" value={selectedBarangay} />

字符串
或者在你的下拉列表中呈现:

<input type="hidden" name={name} value={selected} />

相关问题