T
TanStack2mo ago
extended-salmon

How do I redirect a user after successfully submitting a form?

I'm currently using the set up exactly as outlined in the Next.js integration docs, and using redirect from next/navigation inside the Server Action. However, when submitting, I see some odd behavior where the validations run once more after my server action, and then I see some errors briefly on the form before it finally redirects. Is there a canonical way to redirect? (I searched the docs and the Discord for "redirect" and found nothing)
5 Replies
extended-salmon
extended-salmonOP2mo ago
Commenting out the validators here solves the issue, kind of (it really doesn't because before redirecting the form can be quickly submitted again if the user has a slow connection, as isSubmitting is set to false and canSubmit is set to true). Moreover, as described in this thread, things don't work.
const form = useForm({
...usernameFormOptions, // Just default value for `username`
transform: useTransform(
(baseForm) => mergeForm(baseForm, actionState!),
[actionState]
),
// validators: {
// onBlur: usernameFormSchema,
// },
onSubmit: () => {
console.log('UsernameForm onSubmit')
}
});
const form = useForm({
...usernameFormOptions, // Just default value for `username`
transform: useTransform(
(baseForm) => mergeForm(baseForm, actionState!),
[actionState]
),
// validators: {
// onBlur: usernameFormSchema,
// },
onSubmit: () => {
console.log('UsernameForm onSubmit')
}
});
are validators run again after the form action is called?
ratty-blush
ratty-blush2mo ago
that's strange, since the call shouldn't have happened if there were errors. So the errors you see briefly come from the frontend?
extended-salmon
extended-salmonOP2mo ago
yeah, from onChangeAsync which runs a next-safe-action - this is what my field looks like
<form.Field
name="username"
asyncDebounceMs={500}
validators={{
onChangeAsync: async ({ value }) => {
const { data, serverError, validationErrors } = await checkUsernameAvailable({
username: value,
});
console.log('onChangeAsync result', {data, serverError, validationErrors});
if (!data) {
log.error('No data when checking username availability.');
return { message: 'Something went wrong. Refresh?' };
}
if (data.message) {
toast.error(data.message);
return { message: data.message };
}
if (!data.isAvailable) {
return { message: 'That username is already taken' };
}
},
}}
children={/* ... */}
/>
<form.Field
name="username"
asyncDebounceMs={500}
validators={{
onChangeAsync: async ({ value }) => {
const { data, serverError, validationErrors } = await checkUsernameAvailable({
username: value,
});
console.log('onChangeAsync result', {data, serverError, validationErrors});
if (!data) {
log.error('No data when checking username availability.');
return { message: 'Something went wrong. Refresh?' };
}
if (data.message) {
toast.error(data.message);
return { message: data.message };
}
if (!data.isAvailable) {
return { message: 'That username is already taken' };
}
},
}}
children={/* ... */}
/>
and I see "That username is already taken" after submitting (and that username was created by the form submit run right before it)
ratty-blush
ratty-blush2mo ago
in that case, do you notice a second network call of checkUsernameAvailable? It does sound an awful lot like a second request after submission
extended-salmon
extended-salmonOP2mo ago
i agree it does sound like a second request but weirdly i don't see it in the network tab, and i also don't see my console.logs inside the action. these are the only requests - new-preofile, based on the payload, is the submit action (not checkUsernameAvailable), setup is the redirect
No description

Did you find this page helpful?