Skip to content

Commit b1d52b6

Browse files
authored
Fix uncontrolled radios (facebook#10186)
* Fix uncontrolled radios * cherry-pick regression test from master * prettier
1 parent 6d40e0c commit b1d52b6

File tree

3 files changed

+34
-7
lines changed

3 files changed

+34
-7
lines changed

src/renderers/dom/client/__tests__/inputValueTracking-test.js

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
'use strict';
1212

1313
var React = require('React');
14+
var ReactDOM = require('ReactDOM');
1415
var ReactTestUtils = require('ReactTestUtils');
1516
var inputValueTracking = require('inputValueTracking');
1617

@@ -143,16 +144,38 @@ describe('inputValueTracking', function() {
143144
it('should stop tracking', function() {
144145
inputValueTracking.track(mockComponent);
145146

146-
expect(mockComponent._wrapperState.hasOwnProperty('valueTracker')).toBe(
147-
true,
148-
);
147+
expect(mockComponent._wrapperState.valueTracker).not.toEqual(null);
149148

150149
inputValueTracking.stopTracking(mockComponent);
151150

152-
expect(mockComponent._wrapperState.hasOwnProperty('valueTracker')).toBe(
153-
false,
154-
);
151+
expect(mockComponent._wrapperState.valueTracker).toEqual(null);
155152

156153
expect(input.hasOwnProperty('value')).toBe(false);
157154
});
155+
156+
it('does not crash for nodes with custom value property', () => {
157+
// https://github.com/facebook/react/issues/10196
158+
try {
159+
var originalCreateElement = document.createElement;
160+
document.createElement = function() {
161+
var node = originalCreateElement.apply(this, arguments);
162+
Object.defineProperty(node, 'value', {
163+
get() {},
164+
set() {},
165+
});
166+
return node;
167+
};
168+
var div = document.createElement('div');
169+
// Mount
170+
var node = ReactDOM.render(<input type="text" />, div);
171+
// Update
172+
ReactDOM.render(<input type="text" />, div);
173+
// Change
174+
ReactTestUtils.SimulateNative.change(node);
175+
// Unmount
176+
ReactDOM.unmountComponentAtNode(div);
177+
} finally {
178+
document.createElement = originalCreateElement;
179+
}
180+
});
158181
});

src/renderers/dom/client/inputValueTracking.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ function attachTracker(inst, tracker) {
3131
}
3232

3333
function detachTracker(inst) {
34-
delete inst._wrapperState.valueTracker;
34+
inst._wrapperState.valueTracker = null;
3535
}
3636

3737
function getValueFromNode(node) {

src/renderers/dom/shared/ReactDOMComponent.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,10 @@ ReactDOMComponent.Mixin = {
909909
// happen after `_updateDOMProperties`. Otherwise HTML5 input validations
910910
// raise warnings and prevent the new value from being assigned.
911911
ReactDOMInput.updateWrapper(this);
912+
913+
// We also check that we haven't missed a value update, such as a
914+
// Radio group shifting the checked value to another named radio input.
915+
inputValueTracking.updateValueIfChanged(this);
912916
break;
913917
case 'textarea':
914918
ReactDOMTextarea.updateWrapper(this);

0 commit comments

Comments
 (0)