Skip to content

Commit 2019ddc

Browse files
committed
Delete value attribute when defaultValue sets back to null/missing
For some types, this already resets the value, so if we also have a value we want to set that after. So this moves to updating defaultValue before value.
1 parent 18a5a9f commit 2019ddc

File tree

3 files changed

+56
-38
lines changed

3 files changed

+56
-38
lines changed

packages/react-dom-bindings/src/client/ReactDOMInput.js

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -92,38 +92,17 @@ export function updateInputChecked(element: Element, props: Object) {
9292
export function updateInput(element: Element, props: Object) {
9393
const node: HTMLInputElement = (element: any);
9494

95-
updateInputChecked(element, props);
96-
9795
const value = getToStringValue(props.value);
9896
const type = props.type;
9997

100-
if (value != null) {
101-
if (type === 'number') {
102-
if (
103-
// $FlowFixMe[incompatible-type]
104-
(value === 0 && node.value === '') ||
105-
// We explicitly want to coerce to number here if possible.
106-
// eslint-disable-next-line
107-
node.value != (value: any)
108-
) {
109-
node.value = toString((value: any));
110-
}
111-
} else if (node.value !== toString((value: any))) {
112-
node.value = toString((value: any));
113-
}
114-
} else if (type === 'submit' || type === 'reset') {
115-
// Submit/reset inputs need the attribute removed completely to avoid
116-
// blank-text buttons.
117-
node.removeAttribute('value');
118-
return;
119-
}
120-
12198
if (disableInputAttributeSyncing) {
12299
// When not syncing the value attribute, React only assigns a new value
123100
// whenever the defaultValue React prop has changed. When not present,
124101
// React does nothing
125102
if (props.defaultValue != null) {
126103
setDefaultValue(node, props.type, getToStringValue(props.defaultValue));
104+
} else {
105+
node.removeAttribute('value');
127106
}
128107
} else {
129108
// When syncing the value attribute, the value comes from a cascade of
@@ -135,6 +114,8 @@ export function updateInput(element: Element, props: Object) {
135114
setDefaultValue(node, props.type, value);
136115
} else if (props.defaultValue != null) {
137116
setDefaultValue(node, props.type, getToStringValue(props.defaultValue));
117+
} else {
118+
node.removeAttribute('value');
138119
}
139120
}
140121

@@ -154,6 +135,29 @@ export function updateInput(element: Element, props: Object) {
154135
node.defaultChecked = !!props.defaultChecked;
155136
}
156137
}
138+
139+
updateInputChecked(element, props);
140+
141+
if (value != null) {
142+
if (type === 'number') {
143+
if (
144+
// $FlowFixMe[incompatible-type]
145+
(value === 0 && node.value === '') ||
146+
// We explicitly want to coerce to number here if possible.
147+
// eslint-disable-next-line
148+
node.value != (value: any)
149+
) {
150+
node.value = toString((value: any));
151+
}
152+
} else if (node.value !== toString((value: any))) {
153+
node.value = toString((value: any));
154+
}
155+
} else if (type === 'submit' || type === 'reset') {
156+
// Submit/reset inputs need the attribute removed completely to avoid
157+
// blank-text buttons.
158+
node.removeAttribute('value');
159+
return;
160+
}
157161
}
158162

159163
export function postInitInput(

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1166,11 +1166,7 @@ describe('DOMPropertyOperations', () => {
11661166
).toErrorDev(
11671167
'A component is changing a controlled input to be uncontrolled',
11681168
);
1169-
if (disableInputAttributeSyncing) {
1170-
expect(container.firstChild.hasAttribute('value')).toBe(false);
1171-
} else {
1172-
expect(container.firstChild.getAttribute('value')).toBe('foo');
1173-
}
1169+
expect(container.firstChild.hasAttribute('value')).toBe(false);
11741170
expect(container.firstChild.value).toBe('foo');
11751171
});
11761172

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

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1952,11 +1952,7 @@ describe('ReactDOMInput', () => {
19521952
expect(renderInputWithStringThenWithUndefined).toErrorDev(
19531953
'A component is changing a controlled input to be uncontrolled.',
19541954
);
1955-
if (disableInputAttributeSyncing) {
1956-
expect(input.getAttribute('value')).toBe(null);
1957-
} else {
1958-
expect(input.getAttribute('value')).toBe('latest');
1959-
}
1955+
expect(input.getAttribute('value')).toBe(null);
19601956
});
19611957

19621958
it('preserves the value property', () => {
@@ -2002,11 +1998,7 @@ describe('ReactDOMInput', () => {
20021998
'or `undefined` for uncontrolled components.',
20031999
'A component is changing a controlled input to be uncontrolled.',
20042000
]);
2005-
if (disableInputAttributeSyncing) {
2006-
expect(input.hasAttribute('value')).toBe(false);
2007-
} else {
2008-
expect(input.getAttribute('value')).toBe('latest');
2009-
}
2001+
expect(input.hasAttribute('value')).toBe(false);
20102002
});
20112003

20122004
it('preserves the value property', () => {
@@ -2165,4 +2157,30 @@ describe('ReactDOMInput', () => {
21652157
expect(node.hasAttribute('value')).toBe(false);
21662158
});
21672159
});
2160+
2161+
it('should remove previous `defaultValue`', () => {
2162+
const node = ReactDOM.render(
2163+
<input type="text" defaultValue="0" />,
2164+
container,
2165+
);
2166+
2167+
expect(node.value).toBe('0');
2168+
expect(node.defaultValue).toBe('0');
2169+
2170+
ReactDOM.render(<input type="text" />, container);
2171+
expect(node.defaultValue).toBe('');
2172+
});
2173+
2174+
it('should treat `defaultValue={null}` as missing', () => {
2175+
const node = ReactDOM.render(
2176+
<input type="text" defaultValue="0" />,
2177+
container,
2178+
);
2179+
2180+
expect(node.value).toBe('0');
2181+
expect(node.defaultValue).toBe('0');
2182+
2183+
ReactDOM.render(<input type="text" defaultValue={null} />, container);
2184+
expect(node.defaultValue).toBe('');
2185+
});
21682186
});

0 commit comments

Comments
 (0)