Fix update-form reset to use a one-shot flag instead of isDirty - #349
Merged
Conversation
form.formState.isDirty is cleared by the very form.reset() call it was gating, making it a self-referential (and therefore fragile) signal: any code path that re-triggers the effect while the form happens to be pristine resets it again indefinitely, with no correctness guarantee against future changes to the surrounding state machine. Replace it with a plain useRef flag that is set once the form has been filled from the first successful fetch and never cleared again for the lifetime of the component, so the reset can only ever fire once, independent of react-hook-form's dirty tracking.
mnindrazaka
pushed a commit
that referenced
this pull request
Aug 26, 2026
Adds a regression test for the exact bug class fixed by PR #348/#349 (useForm({ values }) forcing the update form to re-sync from fetched data on every render, silently discarding in-progress edits). This locks in the current defaultValues + one-shot reset behavior for ProductUpdateController specifically, since the fix was applied via a broad refactor across 17 controllers and had no per-controller test coverage. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lf13QXF7eFkx1c9KJcbnwS
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
Follow-up to #348. That PR fixed update forms silently discarding in-progress edits by switching
useForm({ values: state.values })todefaultValuesplus an explicitform.reset(state.values)on fetch success, gated on!form.formState.isDirtyso the reset wouldn't fire again after the user started editing.Review feedback on #348 pointed out that
isDirtyis the wrong signal to gate on: it's cleared by the veryform.reset()call it's supposed to guard, making it a self-referential condition whose safety depends on the timing of surrounding state transitions rather than being provably correct.Change
Replace the
isDirtycheck with a plainuseRefflag, set once the form has been filled from the first successful fetch and never cleared again for the component's lifetime:This is fully decoupled from react-hook-form's dirty tracking, so the reset can only ever fire once per mount, by construction — not contingent on how or when the user happens to edit the form.
Applied across all 17 update controllers: Product, Category, Coupon, Expense, Material, RentalCheckin, RentalCheckout, StockCheck, Supplier, Table, Ticket, Transaction, Variant, Wallet, Budget, Calculation, ChecklistTemplate.
Test plan
nx run ui:lint— clean (only pre-existing, unrelated warnings)nx run ui:test— 1158/1158 passinghttps://claude.ai/code/session_019Y4KcC3TX7Z2UCBnbtBQYz
Generated by Claude Code