At submit time, should the payload come from component state or the form's own field set, and what does each cost?
answer
- two candidate sources at submit
- typed-and-owned versus what the document holds
- text, missing names, absent booleans
- a value the browser wrote, never reported
- field set as base, merge the rest
basics
~10 sState gives typed, normalised values, but only for controls the framework owns. The form's field set gives exactly what the document holds and still works with no script, but everything arrives as text.
solid answer
~50 sTwo sources of truth are available at submit. Building from **component state** means the payload is already typed and normalised, the same object the client rules judged, and it can carry values with no control on screen; the cost is that every value must have reached state, so a control the framework does not own, or a value the browser writes without a notification the framework listens for, silently goes missing. Building from the **form's own field set** — the grouping a browser makes from named controls, exposed as `FormData` — gives you precisely what the user submitted and keeps a no-script fallback alive; the cost is that everything is text, unnamed and disabled controls are absent, and derived or hidden values have to be merged in. Most production forms read the field set as the base and merge the few values state alone knows.
go deeper
Know that after intercepting a submit you must gather the values yourself, either from the state your fields write into or from the form's own named controls. Say that nothing is sent automatically once you take over.
Explain both sources and their costs: typed and normalised but only as complete as the bindings, versus exactly what the document holds but all text. Name the classic gaps — a missing name, a disabled field, an unticked checkbox.
Show the production failures: autofill that never reached state, a partial update that read an absent key as unchanged, rules judging a different object from the one sent. Describe the single mapping step that removes the whole class.
Own the decision as a policy: whether forms must submit before hydration, and therefore which source is authoritative product-wide, so field naming and payload shape are not negotiated per screen.
## Two sources of truth at submit When a submission is intercepted, the payload has to be assembled from somewhere. There are exactly two honest sources, and the choice has consequences well past the handler. - **Component state.** A value per field, owned by the framework, written as the user types or as the binding layer reports changes. - **The form's own field set.** The grouping a browser builds from the form's named, enabled controls at the moment of submission — the same set native submission would have sent, reachable in script as `FormData`. ## Side by side | Concern | Payload from state | Payload from the field set | |---|---|---| | Value types | already coerced — numbers, dates, booleans, nested objects | text (and files); every conversion is yours to do | | Completeness | only what actually reached state | exactly the named, enabled controls in the document | | Values with no control | easy — identifiers, computed flags, context live there already | must be merged in, or carried by hidden controls | | Unticked checkboxes / unselected groups | present with a false or empty value | simply absent, which reads as "unchanged" to a careless server | | Works with no script | no — the payload does not exist until code runs | yes — the same markup submits natively | | Coupling | payload shape is independent of markup | payload shape follows control names | | Where bugs come from | a value that never reached state | a missing `name`, or a control disabled for styling reasons | ## What the state source really costs The state source is only as complete as the bindings feeding it. Three ways a value goes missing: 1. A control the framework does not own — a third-party widget, a custom element, an editor that writes into the document itself — changes its value without reporting anything the binding layer listens for. 2. The browser or another script writes the value directly. Autofill and programmatic assignment are the classic cases: the document has the new value, state still holds the old one, and the payload is stale. (Which notification each binding listens for, and which writes fire none, belongs to the input-events side of forms; the consequence at submit is that the payload lies.) 3. A value is deliberately kept out of state for performance and then forgotten when the payload is assembled. The corresponding strength is real: because state is typed and normalised, the object the client rules judged is the object you send, so a rule and the payload can never disagree about what a field held. ## What the field-set source really costs The field set is whatever the document holds, which is both its strength and its trap: - Every value is **text**. A number field yields a string, an empty field yields an empty string rather than a missing value, and the server or an explicit mapping step has to decide what that means. - A control with **no name** contributes nothing. Neither does a **disabled** one — so disabling a field for a visual reason silently removes it from the write. - **Unticked** boolean controls and **unselected** groups are absent rather than false, which a partial-update endpoint will happily read as "leave this alone". - Multiple controls sharing a name produce several entries, so the reading step must handle repetition rather than assuming one value per key. The corresponding strength is progressive enhancement: the same markup submits without any script, which matters for a first paint before the code has loaded, for a failed bundle, and as a floor under accessibility. ## The hybrid most forms converge on Read the field set as the base, then merge what only the framework knows — the record identifier, derived flags, values held outside the form's markup — and run one explicit mapping step that coerces text into the types the API expects and turns absent booleans into explicit falses. Keep that mapping in one place per form so both the client rules and the request see the same object. Go state-first instead when the form is not really a document form at all: a multi-step flow whose state outlives the rendered step, a payload whose shape is nothing like the control tree, or an interface with no meaningful no-script story. ## Deciding in an interview Say what you optimise for. If the form must work before hydration, the field set has to be the source of truth and state becomes an enhancement. If the payload is deeply structured and heavily validated on the client, state is the source and the field set is a fallback path you may not offer at all. What is indefensible is having both sources half-live: rules judging one object while the request sends another.
- Why is an unticked boolean control missing from the field set a real production bug?Because absence and false look identical to a partial-update endpoint. The user unticks a box, the control contributes nothing, the request omits the key, and the server leaves the old true value in place — so the change appears to save and silently does not. The fix is an explicit mapping step that sets a false for every boolean the form owns, or a paired control that always submits a value.
- A form is filled by the browser's autofill and the payload arrives with empty fields. What happened?The values were written into the document without the change notification the framework's binding listens for, so state stayed empty while the fields look filled. Reading the field set at submit would have sent them. Practical mitigations are to read the document's values at submit as the source of truth, or to reconcile state from the field set once before assembling the payload.
- How do you keep client rules and the request from judging different objects?Assemble the payload once, in one mapping function, and feed that exact object to the rules and then to the request. Rules that read state directly while the request reads the field set will eventually disagree — typically on coercion, where a rule sees a number and the request sends an empty string. One object, one coercion step, both consumers downstream of it.
saying these in an interview costs you the question
- Assuming the field set carries typed values, not text
- Trusting state that never received a browser-written value
- Disabling a field for styling and losing it from the write
- Letting rules judge one object while the request sends another
- Treating an absent key as equivalent to false
- Forgetting identifiers that no control on screen carries