feat(react-form): correctly handle client-side validation with NextJS server-action #1299
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Currently, there is no good, standardized way to properly handle client-side validation along with NextJS server-actions. The TanStack form supports server-actions, but the current implementation has one huge drawback: the server-action calls even if the client-side validation fails.
Client-side validation when submitting a form to a server-action is very important, especially for the user experience. The user sees validation errors immediately, instead of waiting for a response from the server. In addition, there is no reason to call a server-action if the client-side validation fails. The server will perform the same validation that takes place on the client side to eventually fail and return an error, so what is the purpose of pointlessly burdening the server?
So the reason for this feature is to make client-side validation with server-actions finally pleasant.
To prevent the server-action from executing,
event.preventDefault()
must be called synchronously. The problem is that form validation can also happen asynchronously, so there is no easy way to handle this. Soevent.preventDefault()
calls immediately, then form validation occurs, and if successful,event.target.requestSubmit()
is called to callonSubmit
again. In the next iteration ofonSubmit
the code knows that it has already been called and the validation has passed, so it does not callevent.preventDefault()
and the server-action can be executed.Some people have tried to implement this simply by calling
event.target.submit()
after successful validation, but with this approach the page is refreshed, so it completely fails with NextJS. I also noticed that callingonSubmit
again doesn't work without this line:await new Promise((resolve) => setTimeout(resolve, 0))
, so it's just a weird trick to make it work.Stopping the execution of the server-action must be done in
onSubmit
, because then we do not lose the progressive enhancement: if the form data is invalid and JavaScript is enabled, then validation is done on the client side, and the server-action call is blocked. Otherwise,onSubmit
cannot be called by the lack of JavaScript, so the server-action is called immediately, and all validation is done on the server, so everything still works correctly.