ui
ui copied to clipboard
[bug]: form.formState.isSubmitting not working in shadcn sonner
Describe the bug
await is not needed when I try to use toast.promise() in shadcn sonner, thats why the state in form.formState.isSubmitting is always false
Affected component/components
Sonner
How to reproduce
- Create a form uisng
react-hook-form - Create a form action with a
toast.promise()to handle api response - See that the supposedly disabled components like textfield, buttons, etc in the form while loading are still enabled since
toast.promise()doesn't need to be marked withawait
Minimal code to reproduce issue:
'use client'
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { toast } from 'sonner'
import { useForm } from 'react-hook-form'
import { z } from 'zod'
import { zodResolver } from '@hookform/resolvers/zod'
const formSchema = z.object({
name: z.string().min(1, { message: 'Name is required' }),
})
export default function Sample() {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
name: '',
},
})
async function onSubmit(values: z.infer<typeof formSchema>) {
toast.promise(
new Promise<void>((resolve, reject) => {
setTimeout(() => {
resolve()
}, 3000)
}),
{
loading: 'Loading ...',
success: () => {
form.reset()
return `Done! Name is ${values.name}`
},
error: (err) => {
return `${err}`
},
},
)
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Username</FormLabel>
<FormControl>
<Input
disabled={form.formState.isSubmitting}
placeholder="Enter your name"
{...field}
/>
</FormControl>
<FormDescription>
This is your public display name.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<Button disabled={form.formState.isSubmitting} type="submit">
Submit
</Button>
</form>
</Form>
)
}
Codesandbox/StackBlitz link
No response
Logs
No response
System Info
Processor Intel(R) Core(TM) i5-10300H CPU @ 2.50GHz 2.50 GHz
Installed RAM 24.0 GB (23.8 GB usable)
System type 64-bit operating system, x64-based processor
Pen and touch No pen or touch input is available for this display
Browser: Brave, MS Edge
Before submitting
- [X] I've made research efforts and searched the documentation
- [X] I've searched for existing issues
you need to do const { formState: { isSubmitting } } = useForm... in order to make it work as per the react hook form docs said:
Read the formState before render to subscribe the form state through the Proxy
but the approach in shadcn is const form = useForm... and use this form in <Form {...form}>...
im trying to find a way to do this in shadcn too
You can wrap toast.promise into a util function to make it return a Promise. Sonner sadly exports no types so you need to copy its type itself. I made success and error required because of resolve and reject
export function toastPromise<T>(
promise: Promise<T>,
args: {
loading?: string | React.ReactNode;
success: string | React.ReactNode;
error: string | React.ReactNode;
description?: string | React.ReactNode;
finally?: () => void | Promise<void>;
}
): Promise<T> {
return new Promise((resolve, reject) => {
toast.promise(promise, {
...args,
success: (data) => {
resolve(data);
return args.success;
},
error: (err) => {
reject(err);
return args.error;
}
});
});
}
Now instead of
function onSubmit(values: z.infer<formSchema>) {
toast.promise(
new Promise((resolve) => setTimeout(resolve, 1000)),
{
loading: 'Saving...',
success: 'Saved',
error: 'Something went wrong'
}
);
}
You can use
import { toastPromise } from '~/lib/utils';
async function onSubmit(values: z.infer<formSchema>) {
await toastPromise(
new Promise((resolve) => setTimeout(resolve, 1000)),
{
loading: 'Saving...',
success: 'Saved',
error: 'Something went wrong'
}
);
}
This issue has been automatically marked as stale due to one year of inactivity. It will be closed in 7 days unless there’s further input. If you believe this issue is still relevant, please leave a comment or provide updated details. Thank you. (This is an automated message)
This issue has been automatically closed due to one year of inactivity. If you’re still experiencing a similar problem or have additional details to share, please open a new issue following our current issue template. Your updated report helps us investigate and address concerns more efficiently. Thank you for your understanding! (This is an automated message)
is there now a better fix for this?