fix(useController): reflect cleared parent object in controlled fields (#13550) - #13553
Merged
bluebill1049 merged 4 commits intoJun 30, 2026
Merged
Conversation
When a parent object field is replaced (e.g. set to null via setValue), controlled fields subscribed to a nested path were not notified because useController subscribes with exact: true and shouldSubscribeByName only matched on strict name equality. As a result the controlled value went out of sync with form state (getValues/useWatch). Make exact matching also notify subscribers when an ancestor path changes (currentName starts with signalName + '.'), while still excluding sibling and substring-only names (e.g. data vs database). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
bluebill1049
approved these changes
Jun 30, 2026
KATT
added a commit
to KATT/react-hook-form
that referenced
this pull request
Jul 3, 2026
…bmitting-cypress-jest * origin/master: 🐞 fix(flatten): preserve Date values as leaf nodes (react-hook-form#13566) Revert "docs: fix grammar in demo descriptions (react-hook-form#13565)" (react-hook-form#13568) Revert "test: remove duplicate UseFieldArray slug (react-hook-form#13564)" (react-hook-form#13567) test: remove duplicate UseFieldArray slug (react-hook-form#13564) docs: fix grammar in demo descriptions (react-hook-form#13565) 🐞 fix(useController): reflect cleared parent object in controlled fields (react-hook-form#13550) (react-hook-form#13553) 📖 docs: replace dead /api links with /docs in locale READMEs (react-hook-form#13561) 🐛 fix(unset): guard against prototype keyword path traversal (react-hook-form#13559) (react-hook-form#13560) 📖 docs: replace retired /jp, /pt, /zh subdomain links in locale READMEs (react-hook-form#13556)
KATT
added a commit
to KATT/react-hook-form
that referenced
this pull request
Jul 3, 2026
…ssubmitting * repro/activity-issubmitting-vitest: 🐞 fix(flatten): preserve Date values as leaf nodes (react-hook-form#13566) Revert "docs: fix grammar in demo descriptions (react-hook-form#13565)" (react-hook-form#13568) Revert "test: remove duplicate UseFieldArray slug (react-hook-form#13564)" (react-hook-form#13567) test: remove duplicate UseFieldArray slug (react-hook-form#13564) docs: fix grammar in demo descriptions (react-hook-form#13565) 🐞 fix(useController): reflect cleared parent object in controlled fields (react-hook-form#13550) (react-hook-form#13553) 📖 docs: replace dead /api links with /docs in locale READMEs (react-hook-form#13561) 🐛 fix(unset): guard against prototype keyword path traversal (react-hook-form#13559) (react-hook-form#13560) 📖 docs: replace retired /jp, /pt, /zh subdomain links in locale READMEs (react-hook-form#13556)
1 task
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.
Fixes #13550
Problem
When a parent object field is replaced wholesale via
setValue(for example settingdatatonullwhen there are controlled fields ondata.type), the controlled fields kept their stale value and went out of sync withgetValues()/useWatch.Root cause
useControllersubscribes throughuseWatchwithexact: true. InshouldSubscribeByName, exact matching only accepted strict name equality (currentName === signalName).setValue('data', null)emits a change withname: 'data', which never matches the child subscriptiondata.type, so the controlled field was never notified and never re-rendered.This is also why
useWatch(which defaults toexact: false) reflected the cleared value whileuseControllerdid not — exactly the mismatch reported in the issue.Fix
In exact mode, also notify a subscriber when the changed (signal) name is a path ancestor of the subscribed name:
The
+ '.'boundary keeps siblings and substring-only names from matching (e.g.datadoes not matchdatabase, anddata.otherdoes not matchdata.type). Descendant-only signals are still excluded under exact matching, preserving the documented purpose ofexact.Validation
useController.test.tsx: aftersetValue('data', { type: 'foo' })thensetValue('data', null), the controlled value becomesundefinedand stays in sync withuseWatch.shouldSubscribeByName.test.tscovering ancestor matches and the sibling/substring exclusions (datavsdatabase).pnpm test(full suite): 1182 passed.shouldSubscribeByName,useController,useWatch,controller,setValue,useFormState— all green.eslintclean on changed files;tsc --noEmitpasses.Not a duplicate
There are no open PRs addressing #13550 or the exact-subscription ancestor-notification gap. The change is limited to
shouldSubscribeByName(single conditional) plus tests; no public API orexactsemantics for sibling/descendant matching are altered.