diff --git a/packages/react-dom/src/__tests__/ReactDOMTextarea-test.js b/packages/react-dom/src/__tests__/ReactDOMTextarea-test.js
index c9d4a9d8a2d1d..2dc47a6df1a44 100644
--- a/packages/react-dom/src/__tests__/ReactDOMTextarea-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMTextarea-test.js
@@ -426,6 +426,46 @@ describe('ReactDOMTextarea', () => {
ReactDOM.render(, container);
});
+ it('does not set textContent if value is unchanged', () => {
+ const container = document.createElement('div');
+ let node;
+ let instance;
+ // Setting defaultValue on a textarea is equivalent to setting textContent,
+ // and is the method we currently use, so we can observe if defaultValue is
+ // is set to determine if textContent is being recreated.
+ // https://html.spec.whatwg.org/#the-textarea-element
+ let defaultValue;
+ const set = jest.fn(value => {
+ defaultValue = value;
+ });
+ const get = jest.fn(value => {
+ return defaultValue;
+ });
+ class App extends React.Component {
+ state = {count: 0, text: 'foo'};
+ componentDidMount() {
+ instance = this;
+ }
+ render() {
+ return (
+
+ {this.state.count}
+
+ );
+ }
+ }
+ ReactDOM.render(, container);
+ defaultValue = node.defaultValue;
+ Object.defineProperty(node, 'defaultValue', {get, set});
+ instance.setState({count: 1});
+ expect(set.mock.calls.length).toBe(0);
+ });
+
describe('When given a Symbol value', () => {
it('treats initial Symbol value as an empty string', () => {
const container = document.createElement('div');
diff --git a/packages/react-dom/src/client/ReactDOMTextarea.js b/packages/react-dom/src/client/ReactDOMTextarea.js
index a0b244afcd205..b1bdcdd00f0b1 100644
--- a/packages/react-dom/src/client/ReactDOMTextarea.js
+++ b/packages/react-dom/src/client/ReactDOMTextarea.js
@@ -128,6 +128,7 @@ export function initWrapperState(element: Element, props: Object) {
export function updateWrapper(element: Element, props: Object) {
const node = ((element: any): TextAreaWithWrapperState);
const value = getToStringValue(props.value);
+ const defaultValue = getToStringValue(props.defaultValue);
if (value != null) {
// Cast `value` to a string to ensure the value is set correctly. While
// browsers typically do this as necessary, jsdom doesn't.
@@ -136,12 +137,12 @@ export function updateWrapper(element: Element, props: Object) {
if (newValue !== node.value) {
node.value = newValue;
}
- if (props.defaultValue == null) {
+ if (props.defaultValue == null && node.defaultValue !== newValue) {
node.defaultValue = newValue;
}
}
- if (props.defaultValue != null) {
- node.defaultValue = toString(getToStringValue(props.defaultValue));
+ if (defaultValue != null) {
+ node.defaultValue = toString(defaultValue);
}
}