Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix input tracking bug #26627

Merged
merged 1 commit into from
Apr 18, 2023
Merged

Fix input tracking bug #26627

merged 1 commit into from
Apr 18, 2023

Conversation

sophiebits
Copy link
Collaborator

In 2019ddc, we changed to set .defaultValue before .value on updates. In some cases, setting .defaultValue causes .value to change, and since we only set .value if it has the wrong value, this resulted in us not assigning to .value, which resulted in inputValueTracking not knowing the right value. See new test added.

My fix here is to (a) move the value setting back up first and (b) narrowing the fix in the aforementioned PR to newly remove the value attribute only if it defaultValue was previously present in props.

The second half is necessary because for types where the value property and attribute are indelibly linked (hidden checkbox radio submit image reset button, i.e. spec modes default or default/on from https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default), we can't remove the value attribute after setting .value, because that will undo the assignment we just did! That is, not having (b) makes all of those types fail to handle updating props.value.

This code is incredibly hard to think about but I think this is right (or at least, as right as the old code was) because we set .value here only if the nextProps.value != null, and we now remove defaultValue only if lastProps.defaultValue != null. These can't happen at the same time because we have long warned if value and defaultValue are simultaneously specified, and also if a component switches between controlled and uncontrolled.

Also, it fixes the test in #26626.

@facebook-github-bot facebook-github-bot added CLA Signed React Core Team Opened by a member of the React Core Team labels Apr 14, 2023
@react-sizebot
Copy link

react-sizebot commented Apr 14, 2023

Comparing: d121c67...38134f5

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.min.js +0.04% 164.42 kB 164.49 kB = 51.69 kB 51.69 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js +0.06% 166.86 kB 166.96 kB +0.05% 52.34 kB 52.37 kB
facebook-www/ReactDOM-prod.classic.js +0.15% 564.45 kB 565.31 kB +0.08% 99.40 kB 99.48 kB
facebook-www/ReactDOM-prod.modern.js +0.16% 548.24 kB 549.10 kB +0.09% 96.71 kB 96.79 kB

Significant size changes

Includes any change greater than 0.2%:

(No significant changes)

Generated by 🚫 dangerJS against 38134f5

Copy link
Member

@rickhanlonii rickhanlonii left a comment

Choose a reason for hiding this comment

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

Confirmed this fixes the repo too 🤘

@sebmarkbage
Copy link
Collaborator

nextProps.value != null, and we now remove defaultValue only if lastProps.defaultValue != null. These can't happen at the same time

I don't get this part. One is lastProps and one is nextProps so they wouldn't have to be specified at the same time.

<input defaultValue="a" />
<input value="b" />

We might not remove the attribute in the second case if we're syncing input attributes, but we would if we're not. Regardless it's not for the stated reason. Not sure if this helps.

@sophiebits
Copy link
Collaborator Author

because we have long warned if value and defaultValue are simultaneously specified, and also if a component switches between controlled and uncontrolled.

@sebmarkbage
Copy link
Collaborator

I see. I guess I don't consider that warning very reliable. Since it can happen at very unexpected ways late in prod and not development. E.g. unexpected reconciliation of two cases.

In facebook@2019ddc, we changed to set .defaultValue before .value on updates. In some cases, setting .defaultValue causes .value to change, and since we only set .value if it has the wrong value, this resulted in us not assigning to .value, which resulted in inputValueTracking not knowing the right value. See new test added.

My fix here is to (a) move the value setting back up first and (b) narrowing the fix in the aforementioned PR to newly remove the value attribute only if it defaultValue was previously present in props.

The second half is necessary because for types where the value property and attribute are indelibly linked (hidden checkbox radio submit image reset button, i.e. spec modes default or default/on from https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default), we can't remove the value attribute after setting .value, because that will undo the assignment we just did! That is, not having (b) makes all of those types fail to handle updating props.value.

This code is incredibly hard to think about but I think this is right (or at least, as right as the old code was) because we set .value here only if the nextProps.value != null, and we now remove defaultValue only if lastProps.defaultValue != null. These can't happen at the same time because we have long warned if value and defaultValue are simultaneously specified, and also if a component switches between controlled and uncontrolled.

Also, it fixes the test in facebook#26626.
@sophiebits sophiebits merged commit b433c37 into facebook:main Apr 18, 2023
github-actions bot pushed a commit that referenced this pull request Apr 18, 2023
In
2019ddc,
we changed to set .defaultValue before .value on updates. In some cases,
setting .defaultValue causes .value to change, and since we only set
.value if it has the wrong value, this resulted in us not assigning to
.value, which resulted in inputValueTracking not knowing the right
value. See new test added.

My fix here is to (a) move the value setting back up first and (b)
narrowing the fix in the aforementioned PR to newly remove the value
attribute only if it defaultValue was previously present in props.

The second half is necessary because for types where the value property
and attribute are indelibly linked (hidden checkbox radio submit image
reset button, i.e. spec modes default or default/on from
https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default),
we can't remove the value attribute after setting .value, because that
will undo the assignment we just did! That is, not having (b) makes all
of those types fail to handle updating props.value.

This code is incredibly hard to think about but I think this is right
(or at least, as right as the old code was) because we set .value here
only if the nextProps.value != null, and we now remove defaultValue only
if lastProps.defaultValue != null. These can't happen at the same time
because we have long warned if value and defaultValue are simultaneously
specified, and also if a component switches between controlled and
uncontrolled.

Also, it fixes the test in #26626.

DiffTrain build for [b433c37](b433c37)
kassens pushed a commit to kassens/react that referenced this pull request Apr 21, 2023
, facebook#26595, facebook#26596, facebook#26627

- Refactor some controlled component stuff (facebook#26573)
- Don't update textarea defaultValue and input checked unnecessarily (facebook#26580)
- Diff properties in the commit phase instead of generating an update payload (facebook#26583)
- Move validation of text nesting into ReactDOMComponent  (facebook#26594)
- Remove initOption special case (facebook#26595)
- Use already extracted values instead of reading off props for controlled components (facebook#26596)
- Fix input tracking bug (facebook#26627)
github-actions bot pushed a commit that referenced this pull request Apr 21, 2023
- Refactor some controlled component stuff (#26573)
- Don't update textarea defaultValue and input checked unnecessarily (#26580)
- Diff properties in the commit phase instead of generating an update payload (#26583)
- Move validation of text nesting into ReactDOMComponent  (#26594)
- Remove initOption special case (#26595)
- Use already extracted values instead of reading off props for controlled components (#26596)
- Fix input tracking bug (#26627)

DiffTrain build for [ded4a78](ded4a78)
kassens pushed a commit that referenced this pull request Apr 21, 2023
- Refactor some controlled component stuff (#26573)
- Don't update textarea defaultValue and input checked unnecessarily (#26580)
- Diff properties in the commit phase instead of generating an update payload (#26583)
- Move validation of text nesting into ReactDOMComponent  (#26594)
- Remove initOption special case (#26595)
- Use already extracted values instead of reading off props for controlled components (#26596)
- Fix input tracking bug (#26627)
EdisonVan pushed a commit to EdisonVan/react that referenced this pull request Apr 15, 2024
In
facebook@2019ddc,
we changed to set .defaultValue before .value on updates. In some cases,
setting .defaultValue causes .value to change, and since we only set
.value if it has the wrong value, this resulted in us not assigning to
.value, which resulted in inputValueTracking not knowing the right
value. See new test added.

My fix here is to (a) move the value setting back up first and (b)
narrowing the fix in the aforementioned PR to newly remove the value
attribute only if it defaultValue was previously present in props.

The second half is necessary because for types where the value property
and attribute are indelibly linked (hidden checkbox radio submit image
reset button, i.e. spec modes default or default/on from
https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default),
we can't remove the value attribute after setting .value, because that
will undo the assignment we just did! That is, not having (b) makes all
of those types fail to handle updating props.value.

This code is incredibly hard to think about but I think this is right
(or at least, as right as the old code was) because we set .value here
only if the nextProps.value != null, and we now remove defaultValue only
if lastProps.defaultValue != null. These can't happen at the same time
because we have long warned if value and defaultValue are simultaneously
specified, and also if a component switches between controlled and
uncontrolled.

Also, it fixes the test in facebook#26626.
bigfootjon pushed a commit that referenced this pull request Apr 18, 2024
In
2019ddc,
we changed to set .defaultValue before .value on updates. In some cases,
setting .defaultValue causes .value to change, and since we only set
.value if it has the wrong value, this resulted in us not assigning to
.value, which resulted in inputValueTracking not knowing the right
value. See new test added.

My fix here is to (a) move the value setting back up first and (b)
narrowing the fix in the aforementioned PR to newly remove the value
attribute only if it defaultValue was previously present in props.

The second half is necessary because for types where the value property
and attribute are indelibly linked (hidden checkbox radio submit image
reset button, i.e. spec modes default or default/on from
https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default),
we can't remove the value attribute after setting .value, because that
will undo the assignment we just did! That is, not having (b) makes all
of those types fail to handle updating props.value.

This code is incredibly hard to think about but I think this is right
(or at least, as right as the old code was) because we set .value here
only if the nextProps.value != null, and we now remove defaultValue only
if lastProps.defaultValue != null. These can't happen at the same time
because we have long warned if value and defaultValue are simultaneously
specified, and also if a component switches between controlled and
uncontrolled.

Also, it fixes the test in #26626.

DiffTrain build for commit b433c37.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed React Core Team Opened by a member of the React Core Team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants