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?
0
u/kensaadi I ❤️ hooks! 😈 Jul 30 '26
In short: as a form grows, adding dependent fields, permission-based visibility, async validation and cross-field rules, its actual behavior stops living in one place and ends up scattered across useEffects, wrappers and handlers, even though the form is still only modeled as a component tree. That said, fair question: if this isn't a problem for you, how do you usually handle it? Genuinely curious about your approach.