Eliminate unnecessary numeric equality checks#11751
Eliminate unnecessary numeric equality checks#11751gaearon merged 6 commits intofix-value-assignmentfrom
Conversation
This commit changes the way numeric equality for number inputs works such that it compares against `input.valueAsNumber`. This eliminates quite a bit of branching around numeric equality.
|
Can you explain why the original code was written this way, and why it's no longer necessary despite comments saying something about IE9? |
| ) { | ||
| if (props.type === 'number') { | ||
| // eslint-disable-next-line | ||
| if (node.valueAsNumber !== value && node.value != value) { |
There was a problem hiding this comment.
Actually I wonder if I even need to check valueAsNumber. Everything works as expected in IE9, which does not support this API.
| ) { | ||
| if (props.type === 'number') { | ||
| // eslint-disable-next-line | ||
| if (node.value != value) { |
There was a problem hiding this comment.
This seems to be too good to be true, but this checks out in every browser. Unit tests also confirm it. Have I missed something?
There was a problem hiding this comment.
Worth checking git blame to see why this was introduced.
| ) { | ||
| if (props.type === 'number') { | ||
| // eslint-disable-next-line | ||
| if (node.value != value || (value === 0 && node.value === '')) { |
There was a problem hiding this comment.
Looks like we didn't cover "" to 0 in our unit tests. Added.
Identifying all of the edge cases was a long road, and we didn't have all of the test fixtures and unit tests to cover edge cases in type coercion. It was the result of adding additional branches to cover different cases.
IE9 does not support I think the gist of this is just that we do not need to parse the value as a number. We can make the following reductions (or at least this is my logic so we can try to poke holes in it): if (props.type === 'number') {
// Simulate `input.valueAsNumber`. IE9 does not support it
var valueAsNumber = parseFloat(node.value) || 0;
if (
// eslint-disable-next-line
value != valueAsNumber ||
// eslint-disable-next-line
(value == valueAsNumber && node.value != value)
) {
if (props.type === 'number') {
// Simulate `input.valueAsNumber`. IE9 does not support it
var valueAsNumber = parseFloat(node.value) || 0;
if (
// eslint-disable-next-line
value != valueAsNumber && node.value != value
) {To the best of my ability to test, if (props.type === 'number') {
// eslint-disable-next-line
if (value != node.value && node.value != value) {This is the same check! So finally we get to: if (props.type === 'number') {
// eslint-disable-next-line
if (value != node.value) {The edge case here is that if (props.type === 'number') {
// eslint-disable-next-line
if (if (node.value != value || (value === 0 && node.value === '')) { |
| } | ||
| }); | ||
|
|
||
| it('performs as state change from "" to 0', () => { |
| (value == valueAsNumber && node.value != value) | ||
| ) { | ||
| if (props.type === 'number') { | ||
| // eslint-disable-next-line |
There was a problem hiding this comment.
Can we update this so it's only disabling the coercion rule?
There was a problem hiding this comment.
Great idea. I also moved the loose check after the value === 0 guard to avoid some extra DOM access. 3cdde77
| ) { | ||
| if (props.type === 'number') { | ||
| // eslint-disable-next-line | ||
| if (node.value != value || (value === 0 && node.value === '')) { |
There was a problem hiding this comment.
Before this change the 0/ "" coercion would occur for any type of input. Now it only applies to number inputs. Any chance that breaks something weird?
There was a problem hiding this comment.
Not from my ability to test. The strict equality check covers it.
aweary
left a comment
There was a problem hiding this comment.
It does look like parseFloat and == are logically equivalent in this situation. I can't think of any situation where it fails, so assuming all the fixtures pass in the supported browsers this LGTM
|
I'll check this into #11741 in a bit and that one should be good to go. |
…1741) * Ensure value and defaultValue do not assign functions and symbols * Eliminate assignProperty method from ReactDOMInput * Restore original placement of defaultValue reservedProp * Reduce branching. Make assignment more consistent * Control for warnings in symbol/function tests * Add boolean to readOnly assignments * Tweak the tests * Invalid value attributes should convert to an empty string * Revert ChangeEventPlugin update. See #11746 * Format * Replace shouldSetAttribute call with value specific type check DOMProperty.shouldSetAttribute runs a few other checks that aren't appropriate for determining if a value or defaultValue should be assigned on an input. This commit replaces that call with an input specific check. * Remove unused import * Eliminate unnecessary numeric equality checks (#11751) * Eliminate unnecessary numeric equality checks This commit changes the way numeric equality for number inputs works such that it compares against `input.valueAsNumber`. This eliminates quite a bit of branching around numeric equality. * There is no need to compare valueAsNumber * Add test cases for empty string to 0. * Avoid implicit boolean JSX props * Split up numeric equality test to isolate eslint disable command * Fix typo in ReactDOMInput test * Add todos * Update the attribute table
This commit changes the way numeric equality for number inputs works such that it compares loose equality for numbers. This seems sufficient, and eliminates quite a bit of branching around numeric equality.
This additionally addresses Flow type issues on #11741, and it is based off that branch
Test plan:
Tested in: