Mel
Mel

Reputation: 2715

Supabase form reset after successful submit with nextjs app router

I am trying to figure out how to get my form to reset() after it submits in nextjs (app router).

My form has:

"use client"
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs';
import { useEffect, useState } from 'react';



import { addRegion } from "../../actions/newRegionFormSubmit";

type Regions = Database['public']['Tables']['feeds']['Row'];

export default function AddRegions({ region }: { region?: Regions; }) {
  
  const supabase = createClientComponentClient<Database>()

  const [regions, setRegions] = useState<any[]>([]);

  

  useEffect(() => {
    console.log("Inside useEffect");

    // Fetch regions
    const fetchRegions = async () => {
        const { data, error } = await supabase.from('regions').select('*');
        
        console.log("Fetch result:", data, error);
        
        if (error) {
            console.error("Error fetching publishers:", error);
        } else {
            setRegions(data || []);
        }
    };

    fetchRegions();

}, []);

  
  const handleFormSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const formData = new FormData(e.currentTarget as HTMLFormElement);
   
    try {
      await addRegion(formData);
      console.log("Feed added successfully");
      // document.getElementById("handleFormSubmit").reset();

      // how can i reset the form after it submits?
    } catch (error) {
      if (error && typeof error === 'object' && "message" in error) {
        console.error("Error from server action:", error.message);
    }
    }
  };

  return (
    <div>
      <form onSubmit={handleFormSubmit}>
        <div>
          <p className="text-lg text-dark pb-4 font-baron">Add a region</p>  
          <label>Full Region</label>  
          <input name="regionalName" className="bg-lighter border-none w-full mb-2" />
          </div>
          <div>
          <label>Broader scope (optional)</label>
          <input name="partOf" className="bg-lighter border-none  w-full" />
        </div>

        <button type="submit" className="bg-linkStyle hover:bg-linkOnHover text-light my-4 py-2 px-4 rounded-none">Submit</button>
      </form>


    </div>
  );
}

My form action has:

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

export const addRegion = async (formData: FormData) => {
    const regionalName = String(formData.get("regionalName"));
    const partOf = String(formData.get("partOf"));
  
    const supabase = createServerActionClient<Database>({ cookies });

  
    if (!regionalName) throw new Error("Please enter a region");

    console.log("attempting to add feed", { regionalName });

    const { error } = await supabase.from("regions").insert({ 
        regionalName,
        partOf,
    });
    if (error) throw new Error(error.message);
    
    revalidatePath("/");
}

I have tried the line shown in commenting - but its obviously incorrect. I can't find a better idea. The form submits and the db updates, but the form wont refresh.

NEXT ATTEMPT

For my next attempt, I tried to add the useRef handler from react. I can't figure out how to properly introduce this. This attempt:

"use client"
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs';
import { useRef, useEffect, useState } from 'react';



import { addRegion } from "../../actions/newRegionFormSubmit";

type Regions = Database['public']['Tables']['feeds']['Row'];

export default function AddRegions({ region }: { region?: Regions; }) {
  
  const supabase = createClientComponentClient<Database>()

  const [regions, setRegions] = useState<any[]>([]);

  const formRef = useRef<HTMLFormElement>(null)

  

  useEffect(() => {
    console.log("Inside useEffect");

    // Fetch regions
    const fetchRegions = async () => {
        const { data, error } = await supabase.from('regions').select('*');
        
        console.log("Fetch result:", data, error);
        
        if (error) {
            console.error("Error fetching publishers:", error);
        } else {
            setRegions(data || []);
        }
    };

    fetchRegions();

}, []);

  
  const handleFormSubmit = async (formData: FormData) => {
    const result = await addRegion(formData) 
    formRef.current?.reset()  
    
    }




  return (
    <div>
      <form onSubmit={handleFormSubmit} ref={formRef}>
        <div>
          <p className="text-lg text-dark pb-4 font-baron">Add a region</p>  
          <label>Full Region</label>  
          <input name="regionalName" className="bg-lighter border-none w-full mb-2" />
          </div>
          <div>
          <label>Broader scope (optional)</label>
          <input name="partOf" className="bg-lighter border-none  w-full" />
        </div>

        <button type="submit" className="bg-linkStyle hover:bg-linkOnHover text-light my-4 py-2 px-4 rounded-none">Submit</button>
      </form>


    </div>
  );
}

When I try this, the error says:

Type '(formData: FormData) => Promise' is not assignable to type 'FormEventHandler'. Types of parameters 'formData' and 'event' are incompatible. Type 'FormEvent' is missing the following properties from type 'FormData': append, delete, get, getAll, and 7 more.ts(2322) index.d.ts(1452, 9): The expected type comes from property 'onSubmit' which is declared here on type 'DetailedHTMLProps<FormHTMLAttributes, HTMLFormElement>' (property) DOMAttributes.onSubmit?: FormEventHandler | undefined

Upvotes: 2

Views: 623

Answers (2)

Tom
Tom

Reputation: 244

There's a couple of things to update in your code:

  1. The onSubmit property of the <form> tag is an event handler. You can see from the MDN docs that the function getting called when this even happens gets passed in an event parameter. The function doesn't get passed in the form data that you're expecting formData: FormData. You need another way to access the form data in your handleFormSubmit function. The event type is SubmitEvent, which has a submitter property. This gives you access to the form, where you can extract the data.
  2. Your handleFormSubmit function is marked as async. onSubmit is not expecting an async function. You can workaround this by doing:
<form onSubmit={()=>{handleFormSubmit()}} ref={formRef}>

const formData = new FormData(e.submitter() as HTMLFormElement);

If you make the first update suggested here, you'll be able to call .reset() on the form returned by submitter.

Upvotes: 0

Mel
Mel

Reputation: 2715

I can't find any documentation explaining this, but so far, it is working. I'm still looking for an answer to explain what needs to happen to use form reset in next app router.

const handleFormSubmit = async (event: React.FormEvent) => { event.preventDefault(); // prevent default form submission behavior

if (formRef.current) {
    const formData = new FormData(formRef.current);
    await addRegion(formData);
    formRef.current.reset();
}

};

Upvotes: 0

Related Questions