Repository navigation
fix(forms): align Vue, Svelte and Solid submit handling with React - #761
Merged
Merged
Conversation
…olid A second submit aborts the first through the router, and the first's cleanup then cleared `pending` while the second was still running. An older submit that still completed could also apply its errors, success state and defaults. Island forms have no abort, so an older response could overwrite a newer result, reload the page or redirect. Only the latest submit now updates form state or changes the page, matching the request ID guard React's useIslandForm gained in voidzero-dev#738. An older submit's real failure still rejects its own promise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d Solid On success these forms saved their values as of the response, so anything typed while the request was in flight counted as saved: `hasChanges` read false and `reset()` restored text that was never submitted. `resetOnSuccess` also wiped those edits, and page forms sent a shallow copy that shared nested values with the live form. Each form now takes a deep copy when submit starts, sends it and saves it as the new defaults. `resetOnSuccess` only clears the data if it has not changed since submit. This matches what React's forms have done since voidzero-dev#738. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
yangshun
marked this pull request as draft
November 9, 2026 12:40
yangshun
force-pushed
the
fix/form-overlapping-submits
branch
from
November 9, 2026 12:40
5a81d35 to
e4ca5a7
Compare
yangshun
marked this pull request as ready for review
November 9, 2026 12:53
yangshun
commented
Nov 9, 2026
| @@ -0,0 +1,259 @@ | |||
| import { createComponent, createRoot } from 'solid-js'; | |||
Collaborator
Author
There was a problem hiding this comment.
Solid gets a new test file because these tests need its client runtime, since createMemo only evaluates once on the server runtime that use-form.test.ts uses. vi.mock is file-wide, so adding them there would have switched the existing tests too.
cpojer
self-requested a review
November 9, 2026 22:35
cpojer
approved these changes
Nov 9, 2026
cpojer
left a comment
Member
There was a problem hiding this comment.
Starting to feel like all the UI frameworks are the same.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Brings
useFormanduseIslandFormin Vue, Svelte and Solid in line with React, fixing two bugs in how they handle a submit that is still in flight.Why the adapters differ
All four adapters used to share these bugs. #738 fixed them in React only, so React has guarded concurrent submits and kept submitted values since then, while Vue, Svelte and Solid have not.
The issues
1. An older submit could still change the form when a newer one was running (
3c9ddc5ae)The forms tracked submits with flags and did not record which one was latest.
finallythen setpending = falsewhile the second was still running. A submit button disabled bypendingbecame clickable again mid-request. An older submit that still completed could also apply its errors, success state and defaults.pending, reload the page or redirect, whichever finished first.2. Edits made during a submit counted as saved (
e4ca5a713)On success, the forms saved their values as of the response rather than as of the submit.
hasChangesreadfalse, andreset()restored text that was never sent.resetOnSuccesswiped anything typed while the request was in flight.The fix
requestIdandlatestRequestId, the same names React's island form uses. Only the latest submit updates state, reloads or redirects. An older submit's real failure still rejects its own promise.resetOnSuccessonly clears the data if it has not changed since submit.hasChangesandresetOnSuccessdocs now cover edits made during a submit. Most of that diff is the formatter repadding the table.Behaviour that still differs from React
useActionStatequeues them, while Vue, Svelte and Solid abort the first and keep the latest. This PR keeps that difference. The server may still have processed an aborted request.resetOnSuccessedit check: these adapters compare values, because their form data is mutated in place, while React compares object identity. Typing something and changing it back counts as unchanged here.Test plan
New tests cover both finishing orders, aborts, older failures, in-flight edits and
resetOnSuccess, based on the React test added in #738. Solid's are in a new file because they need its client runtime. They assert throughreset()rather thanhasChanges, becausecreateStoreandcreateMemodo not track each other under those test mocks.vp run checkpasses (33/33)e4ca5a713vp test runhad 16,106 tests pass and 41 fail, every failure beingbrowserType.launch: Executable doesn't exist, because this machine lacks the Chromium build Playwright 1.65 expects🤖 Generated with Claude Code