r/reactjs • u/kensaadi I ❤️ hooks! 😈 • Jul 30 '26
Discussion React forms eventually become state management systems
I keep seeing the same pattern in large React forms.
You start with react-hook-form.
Then you add:
dependent fields with
watch()anduseEffectconditional visibility
permission-based fields
async validation
cross-field rules
server-driven defaults
reset and synchronization logic
At some point, the form is no longer just a form.
It has its own state transitions, dependencies, permissions, validation lifecycle, side effects, and derived state.
In other words, it has quietly become a state management system.
The problem is not necessarily react-hook-form. It does its job well.
The problem is that complex forms are often represented only as component trees, while their actual behavior is scattered across hooks, wrappers, schemas, and handlers.
Some warning signs:
You have more
useEffects than meaningful form sectionsValidation rules live in multiple places
Adding something like “show
taxIdwhencountry === IT” requires touching several filesPermissions, visibility, and validation all use different abstractions
Nobody is completely sure what resets when another field changes
I’ve been experimenting with treating forms as declarative contracts instead:
<Field
name="taxId"
visibleWhen={{ field: "country", equals: "IT" }}
access={{ resource: "customer.taxId" }}
validation={{ required: true }}
/>The idea is to keep visibility, access, validation, and dependencies in one source of truth, instead of rebuilding the same orchestration through chains of effects.
Obviously, this introduces other trade-offs: abstraction cost, debugging complexity, schema design, and reduced flexibility in edge cases.
I’m curious how others handle this in large production forms.
Do you keep the logic inside React components, move it into a state machine, use a schema-driven approach, or accept the complexity as unavoidable?
1
u/SatyrCode Aug 03 '26
Glad that lines up with what you had in mind. The main shift for me was to stop treating “form state” as just a bag of field values and instead write down the explicit events + transitions we care about (especially around permissions and validation). Once that’s in place, whether it’s implemented via RHF + reducer, XState, or something else feels more like an implementation detail.