Skip to content

fix: ensure each createFormControl.subscribe subscription listens only to the changes it subscribes to#12968

Merged
bluebill1049 merged 8 commits intoreact-hook-form:masterfrom
dusan233:multiple-subscriptions
Dec 7, 2025
Merged

fix: ensure each createFormControl.subscribe subscription listens only to the changes it subscribes to#12968
bluebill1049 merged 8 commits intoreact-hook-form:masterfrom
dusan233:multiple-subscriptions

Conversation

@dusan233
Copy link
Copy Markdown
Contributor

Not sure if its a bug fix or a feature. When you register multiple subscriptions, their formState filters are merged, so the last called subscription will listen on updates for both its own fields and all fields subscribed to by earlier subscriptions.

Example: https://codesandbox.io/p/sandbox/vwfnsk?file=%2Fsrc%2FApp.tsx%3A5%2C18
Steps:

  1. notice that App component is subscribing only to value changes on field "lastName".
  2. type one character into "lastName" field.
  3. notice that "lastName" subscription callback is being called both for value change and fields dirty state being changed as if we subscribed like:
subscribe({
      formState: {
        values: true,
        dirtyFields: true,
      },
      name: 'lastName',
      callback: (state) => {
        console.log('Form state changed:', state);
      },
    });

This PR ensures that each subscription listens only to the changes it subscribes to.

@bluebill1049 bluebill1049 requested a review from Copilot July 16, 2025 11:58
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR isolates subscription filters so that each subscribe call only listens to the specific formState keys it requested, preventing subscriptions from unintentionally accumulating filters.

  • Introduce defaultProxyFormState as the base filter set for every subscription
  • Rename and reinitialize _proxyFormState for clarity
  • Update subscribe to merge only defaultProxyFormState with the incoming props.formState
  • Add a test to verify multiple subscriptions trigger only their own callbacks

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/logic/createFormControl.ts Define defaultProxyFormState and use it in each subscribe call to reset filters
src/tests/useForm/subscribe.test.tsx Add a test ensuring distinct subscriptions only fire for their own field changes
Comments suppressed due to low confidence (2)

src/logic/createFormControl.ts:154

  • [nitpick] The name defaultProxyFormState could be more descriptive or follow the existing private naming pattern (e.g., _defaultProxyFormState or initialProxyFormState) to align with other variables in this module.
  const defaultProxyFormState: ReadFormState = {

src/tests/useForm/subscribe.test.tsx:10

  • [nitpick] Consider renaming the mock callbacks (e.g., firstCallback, secondCallback) for clearer intent in the test.
    const cb2 = jest.fn();

Comment thread src/logic/createFormControl.ts
@bluebill1049 bluebill1049 self-requested a review July 16, 2025 11:59
Comment on lines +1065 to +1068
formState: {
...defaultProxyFormState,
...props.formState,
},
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need this defaultProxyFormState?

what's the diff if we just do:

..._proxyFormState,
...props.formState,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we do still need defaultProxyFormState. The example below also mutates _proxyFormState, so we may end up subscribing to changes in formState that we didn't request in the subscribe call.

const fieldFormState = useFormState({
    name: "field1",
    control,
 });

fieldFormState.touchedFields

Do you want me to create test for this?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want me to create test for this?

yes plz <3

@dusan233 dusan233 requested a review from bluebill1049 October 11, 2025 08:18
@bluebill1049 bluebill1049 merged commit d799a62 into react-hook-form:master Dec 7, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants