Next.js Discord

Discord Forum

Return messages in server actions are not shown or displayed

Unanswered
Jenn posted this in #help-forum
Open in Discord
Original message was deleted.

6 Replies

Form Submission
    'use client'
    
    interface FormData {
      name: string;
      ...the rest of the data
    }
    
    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 [formValue, setFormValue] = useState<FormData>({
       ...rest of the data
      });
    
      return (
        <div className="container mx-auto p-4">
                
          <p aria-live="polite" className="sr-only" role="status">
            {state?.message}
          </p>
    
        <form action={formAction}>
        <MyInput
            id="name"
            label="Water Station Name" 
            name="name"
            value={formValue.name}
            onChange={(event) => setFormValue({ ...formValue, [event.target.name]: event.target.value })}
            required 
            type="text" 
            errors={state.errors}
          /> 
          ... the rest of the input fields
          <SubmitButton />
        </form>
        </div>
      );
    }
Server action
'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')
            ...rest of the data
            
            const {data, error} = await supabase.from('water_refilling_station')
                .insert({
                    station_name,
                    ...rest of the data
                }).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."}
        }
    
    }
Reusable component for the input fields:
interface MyInputProps {
  label: string;
  name: string;
  id: string;
  value: string | number;
  onChange: (event: any) => void; 
  errors: any;
  // onChange: (name: string, value: string | number | null) => void;
  required?: boolean;
  type?: 'text' | 'number';
}

const MyInput: React.FC<MyInputProps> = ({
  label,
  name,
  id,
  value,
  onChange,
  errors,
  required = false,
  type = 'text',
}: MyInputProps) => {

  //extract errors
  let error;
  if(errors && errors[name]) {
    error = errors[name];
  }

  return (
    <div className="mb-4">
      <label className="block text-lg font-semibold text-blue-700 mb-2">{label}</label>
      <input
         type={type} 
         id={id} 
         name={name} 
         required={required} 
         value={value}
         onChange={onChange}
      />
      {error && <p className="text-red-500 text-lg italic mt-2">{error}</p>}
    </div>
  );
};

export default MyInput;