Skip to content

Commit d81c85e

Browse files
committed
Prevent incorrect options SSR hydrate mismatch, fix #11602
Avoid overwrite options children nodes when setting the selected option.
1 parent d0e75dc commit d81c85e

File tree

2 files changed

+34
-2
lines changed

2 files changed

+34
-2
lines changed

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegrationTestUtils');
1313

14+
const TEXT_NODE_TYPE = 3;
15+
1416
let React;
1517
let ReactDOM;
1618
let ReactDOMServer;
@@ -37,6 +39,8 @@ const {
3739
itClientRenders,
3840
renderIntoDom,
3941
serverRender,
42+
streamRender,
43+
clientRenderOnServerString,
4044
} = ReactDOMServerIntegrationUtils(initModules);
4145

4246
describe('ReactDOMServerIntegration', () => {
@@ -45,6 +49,11 @@ describe('ReactDOMServerIntegration', () => {
4549
});
4650

4751
describe('form controls', function() {
52+
function expectNode(node, type, value) {
53+
expect(node).not.toBe(null);
54+
expect(node.nodeType).toBe(type);
55+
expect(node.nodeValue).toMatch(value);
56+
}
4857
describe('inputs', function() {
4958
itRenders('an input with a value and an onChange', async render => {
5059
const e = await render(<input value="foo" onChange={() => {}} />);
@@ -341,6 +350,31 @@ describe('ReactDOMServerIntegration', () => {
341350
);
342351
});
343352

353+
describe('options', function() {
354+
itRenders('an option with multiple text children', async render => {
355+
const e = await render(
356+
<select value="bar" readOnly={true}>
357+
<option value="bar">A {'B'}</option>
358+
</select>,
359+
0,
360+
);
361+
const option = e.options[0];
362+
if (
363+
render === serverRender ||
364+
render === streamRender ||
365+
render === clientRenderOnServerString
366+
) {
367+
// We have three nodes because there is a comment between them.
368+
expect(option.childNodes.length).toBe(3);
369+
expectNode(option.childNodes[0], TEXT_NODE_TYPE, 'A');
370+
expectNode(option.childNodes[2], TEXT_NODE_TYPE, 'B');
371+
} else {
372+
expect(option.childNodes.length).toBe(1);
373+
expectNode(option.childNodes[0], TEXT_NODE_TYPE, 'A B');
374+
}
375+
});
376+
});
377+
344378
describe('user interaction', function() {
345379
let ControlledInput,
346380
ControlledTextArea,

packages/react-dom/src/server/ReactPartialRenderer.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -997,12 +997,10 @@ class ReactDOMServerRenderer {
997997
props = Object.assign(
998998
{
999999
selected: undefined,
1000-
children: undefined,
10011000
},
10021001
props,
10031002
{
10041003
selected: selected,
1005-
children: optionChildren,
10061004
},
10071005
);
10081006
}

0 commit comments

Comments
 (0)