I am using "react-hook-form" and shadcn. I want to show a loading spinner when the user sends the form. The new data is fetched on the page.tsx
each time the query changes. This process takes some time and I want to give the user a feedback, that he has to wait with a loading spinner.
What I tried so far:
Minimal example:
export function DatePickerForm() {
const router = useRouter();
const { from } = useDateRange(); // just receives the from date from the searchParams
const form = useForm<z.infer<typeof FormSchema>>();
async function onSubmit(data: z.infer<typeof FormSchema>) {
const from = format(data.from, "yyyy-MM-dd");
router.push(`/?from=${from}`);
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<div className="flex flex-row space-x-4">
<FormField
control={form.control}
name="from"
render={({ field }) => (
<FormItem className="flex flex-col">
<FormLabel>Von</FormLabel>
<Popover>
<PopoverTrigger asChild>
<FormControl>
<Button
variant={"outline"}
className={cn(
"w-[240px] pl-3 text-left font-normal",
!field.value && "text-muted-foreground"
)}
>
{field.value ? (
format(field.value, "PPP", { locale: de })
) : (
<span>Pick date</span>
)}
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
mode="single"
selected={field.value}
onSelect={field.onChange}
disabled={(date) =>
date > new Date() || date < new Date("1900-01-01")
}
initialFocus
/>
</PopoverContent>
</Popover>
<FormMessage />
</FormItem>
)}
/>
</div>
<Button disabled={//HELP HERE!} type="submit">
{/* //HELP HERE! <Loader2 className="mr-2 h-4 w-4 animate-spin" /> */}
Suchen
</Button>
</form>
</Form>
);
}
You can use useTransition
hook:
import { useRouter } from 'next/navigation'
import { useTransition } from 'react'
'use client'
export function MyComponent() {
const router = useRouter()
const [isPending, startTransition] = useTransition()
function navigate() {
startTransition(() => {
router.push('/sometwhere')
})
}
return (
<div>
<button type="button" onClick={navigate}>Click</button>
{isPending && <p>Navigating...</p>}
</div>
)
}