Skip to content

Commit 994ade9

Browse files
nhunzakerSimek
authored andcommitted
Resubmit: Fix updateWrapper causing re-render textarea, even though their data (facebook#13643)
* fix updateWrapper causing re-render textarea, even though their data has not changed * fix updateWrapper causing re-render textarea, even though their data, prettier-all * minor changes to updateWrapper, add test
1 parent 82e1600 commit 994ade9

File tree

2 files changed

+44
-3
lines changed

2 files changed

+44
-3
lines changed

packages/react-dom/src/__tests__/ReactDOMTextarea-test.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,46 @@ describe('ReactDOMTextarea', () => {
426426
ReactDOM.render(<textarea value={undefined} />, container);
427427
});
428428

429+
it('does not set textContent if value is unchanged', () => {
430+
const container = document.createElement('div');
431+
let node;
432+
let instance;
433+
// Setting defaultValue on a textarea is equivalent to setting textContent,
434+
// and is the method we currently use, so we can observe if defaultValue is
435+
// is set to determine if textContent is being recreated.
436+
// https://html.spec.whatwg.org/#the-textarea-element
437+
let defaultValue;
438+
const set = jest.fn(value => {
439+
defaultValue = value;
440+
});
441+
const get = jest.fn(value => {
442+
return defaultValue;
443+
});
444+
class App extends React.Component {
445+
state = {count: 0, text: 'foo'};
446+
componentDidMount() {
447+
instance = this;
448+
}
449+
render() {
450+
return (
451+
<div>
452+
<span>{this.state.count}</span>
453+
<textarea
454+
ref={n => (node = n)}
455+
value="foo"
456+
onChange={emptyFunction}
457+
/>
458+
</div>
459+
);
460+
}
461+
}
462+
ReactDOM.render(<App />, container);
463+
defaultValue = node.defaultValue;
464+
Object.defineProperty(node, 'defaultValue', {get, set});
465+
instance.setState({count: 1});
466+
expect(set.mock.calls.length).toBe(0);
467+
});
468+
429469
describe('When given a Symbol value', () => {
430470
it('treats initial Symbol value as an empty string', () => {
431471
const container = document.createElement('div');

packages/react-dom/src/client/ReactDOMTextarea.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ export function initWrapperState(element: Element, props: Object) {
128128
export function updateWrapper(element: Element, props: Object) {
129129
const node = ((element: any): TextAreaWithWrapperState);
130130
const value = getToStringValue(props.value);
131+
const defaultValue = getToStringValue(props.defaultValue);
131132
if (value != null) {
132133
// Cast `value` to a string to ensure the value is set correctly. While
133134
// browsers typically do this as necessary, jsdom doesn't.
@@ -136,12 +137,12 @@ export function updateWrapper(element: Element, props: Object) {
136137
if (newValue !== node.value) {
137138
node.value = newValue;
138139
}
139-
if (props.defaultValue == null) {
140+
if (props.defaultValue == null && node.defaultValue !== newValue) {
140141
node.defaultValue = newValue;
141142
}
142143
}
143-
if (props.defaultValue != null) {
144-
node.defaultValue = toString(getToStringValue(props.defaultValue));
144+
if (defaultValue != null) {
145+
node.defaultValue = toString(defaultValue);
145146
}
146147
}
147148

0 commit comments

Comments
 (0)