Reputation: 2715
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
Reputation: 244
There's a couple of things to update in your code:
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.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
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