diff --git a/src/renderers/dom/client/__tests__/inputValueTracking-test.js b/src/renderers/dom/client/__tests__/inputValueTracking-test.js
index 103964cc1d74..8d9c5c9671fb 100644
--- a/src/renderers/dom/client/__tests__/inputValueTracking-test.js
+++ b/src/renderers/dom/client/__tests__/inputValueTracking-test.js
@@ -11,6 +11,7 @@
'use strict';
var React = require('React');
+var ReactDOM = require('ReactDOM');
var ReactTestUtils = require('ReactTestUtils');
var inputValueTracking = require('inputValueTracking');
@@ -143,16 +144,38 @@ describe('inputValueTracking', function() {
it('should stop tracking', function() {
inputValueTracking.track(mockComponent);
- expect(mockComponent._wrapperState.hasOwnProperty('valueTracker')).toBe(
- true,
- );
+ expect(mockComponent._wrapperState.valueTracker).not.toEqual(null);
inputValueTracking.stopTracking(mockComponent);
- expect(mockComponent._wrapperState.hasOwnProperty('valueTracker')).toBe(
- false,
- );
+ expect(mockComponent._wrapperState.valueTracker).toEqual(null);
expect(input.hasOwnProperty('value')).toBe(false);
});
+
+ it('does not crash for nodes with custom value property', () => {
+ // https://github.com/facebook/react/issues/10196
+ try {
+ var originalCreateElement = document.createElement;
+ document.createElement = function() {
+ var node = originalCreateElement.apply(this, arguments);
+ Object.defineProperty(node, 'value', {
+ get() {},
+ set() {},
+ });
+ return node;
+ };
+ var div = document.createElement('div');
+ // Mount
+ var node = ReactDOM.render(, div);
+ // Update
+ ReactDOM.render(, div);
+ // Change
+ ReactTestUtils.SimulateNative.change(node);
+ // Unmount
+ ReactDOM.unmountComponentAtNode(div);
+ } finally {
+ document.createElement = originalCreateElement;
+ }
+ });
});
diff --git a/src/renderers/dom/client/inputValueTracking.js b/src/renderers/dom/client/inputValueTracking.js
index f0086f03a153..5b300d5d05f1 100644
--- a/src/renderers/dom/client/inputValueTracking.js
+++ b/src/renderers/dom/client/inputValueTracking.js
@@ -31,7 +31,7 @@ function attachTracker(inst, tracker) {
}
function detachTracker(inst) {
- delete inst._wrapperState.valueTracker;
+ inst._wrapperState.valueTracker = null;
}
function getValueFromNode(node) {
diff --git a/src/renderers/dom/shared/ReactDOMComponent.js b/src/renderers/dom/shared/ReactDOMComponent.js
index 6c7a1ca8bd01..77d1df67aa5e 100644
--- a/src/renderers/dom/shared/ReactDOMComponent.js
+++ b/src/renderers/dom/shared/ReactDOMComponent.js
@@ -909,6 +909,10 @@ ReactDOMComponent.Mixin = {
// happen after `_updateDOMProperties`. Otherwise HTML5 input validations
// raise warnings and prevent the new value from being assigned.
ReactDOMInput.updateWrapper(this);
+
+ // We also check that we haven't missed a value update, such as a
+ // Radio group shifting the checked value to another named radio input.
+ inputValueTracking.updateValueIfChanged(this);
break;
case 'textarea':
ReactDOMTextarea.updateWrapper(this);