mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Fixes children when using dangerouslySetInnerHtml in a selected <option> (#13078)
* Fixes children when using dangerouslySetInnerHtml in a selected <option>
This fixes an inadvertent cast of undefined children to an empty string when creating an option tag that will be selected:
```
<select defaultValue="test">
<option value='test' dangerouslySetInnerHTML={{ __html: '‏ test'}} />
</select>
```
This causes an invariant error because both children and dangerouslySetInnerHTML are set.
* PR fix and new ReactDOMServerIntegrationForms test
* Account for null case
* Combine test cases into single test
* Add tests for failure cases
* Fix lint
This commit is contained in:
committed by
Dan Abramov
parent
a960d18bc7
commit
da5c87bdfa
@@ -443,6 +443,37 @@ describe('ReactDOMSelect', () => {
|
||||
expect(markup).not.toContain('<option selected="" value="gorilla"');
|
||||
});
|
||||
|
||||
it('should support server-side rendering with dangerouslySetInnerHTML', () => {
|
||||
const stub = (
|
||||
<select defaultValue="giraffe">
|
||||
<option
|
||||
value="monkey"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: 'A monkey!',
|
||||
}}>
|
||||
{undefined}
|
||||
</option>
|
||||
<option
|
||||
value="giraffe"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: 'A giraffe!',
|
||||
}}>
|
||||
{null}
|
||||
</option>
|
||||
<option
|
||||
value="gorilla"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: 'A gorilla!',
|
||||
}}
|
||||
/>
|
||||
</select>
|
||||
);
|
||||
const markup = ReactDOMServer.renderToString(stub);
|
||||
expect(markup).toContain('<option selected="" value="giraffe"');
|
||||
expect(markup).not.toContain('<option selected="" value="monkey"');
|
||||
expect(markup).not.toContain('<option selected="" value="gorilla"');
|
||||
});
|
||||
|
||||
it('should support server-side rendering with multiple', () => {
|
||||
const stub = (
|
||||
<select multiple={true} value={['giraffe', 'gorilla']} onChange={noop}>
|
||||
|
||||
@@ -35,6 +35,7 @@ const {
|
||||
resetModules,
|
||||
itRenders,
|
||||
itClientRenders,
|
||||
itThrowsWhenRendering,
|
||||
renderIntoDom,
|
||||
serverRender,
|
||||
} = ReactDOMServerIntegrationUtils(initModules);
|
||||
@@ -327,6 +328,81 @@ describe('ReactDOMServerIntegration', () => {
|
||||
expectSelectValue(e, 'bar');
|
||||
});
|
||||
|
||||
itRenders(
|
||||
'a select with options that use dangerouslySetInnerHTML',
|
||||
async render => {
|
||||
const e = await render(
|
||||
<select defaultValue="baz" value="bar" readOnly={true}>
|
||||
<option
|
||||
id="foo"
|
||||
value="foo"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: 'Foo',
|
||||
}}>
|
||||
{undefined}
|
||||
</option>
|
||||
<option
|
||||
id="bar"
|
||||
value="bar"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: 'Bar',
|
||||
}}>
|
||||
{null}
|
||||
</option>
|
||||
<option
|
||||
id="baz"
|
||||
value="baz"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: 'Baz',
|
||||
}}
|
||||
/>
|
||||
</select>,
|
||||
1,
|
||||
);
|
||||
expectSelectValue(e, 'bar');
|
||||
},
|
||||
);
|
||||
|
||||
itThrowsWhenRendering(
|
||||
'a select with option that uses dangerouslySetInnerHTML and 0 as child',
|
||||
async render => {
|
||||
await render(
|
||||
<select defaultValue="baz" value="foo" readOnly={true}>
|
||||
<option
|
||||
id="foo"
|
||||
value="foo"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: 'Foo',
|
||||
}}>
|
||||
{0}
|
||||
</option>
|
||||
</select>,
|
||||
1,
|
||||
);
|
||||
},
|
||||
'Can only set one of `children` or `props.dangerouslySetInnerHTML`.',
|
||||
);
|
||||
|
||||
itThrowsWhenRendering(
|
||||
'a select with option that uses dangerouslySetInnerHTML and empty string as child',
|
||||
async render => {
|
||||
await render(
|
||||
<select defaultValue="baz" value="foo" readOnly={true}>
|
||||
<option
|
||||
id="foo"
|
||||
value="foo"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: 'Foo',
|
||||
}}>
|
||||
{''}
|
||||
</option>
|
||||
</select>,
|
||||
1,
|
||||
);
|
||||
},
|
||||
'Can only set one of `children` or `props.dangerouslySetInnerHTML`.',
|
||||
);
|
||||
|
||||
itRenders(
|
||||
'a select value overriding defaultValue no matter the prop order',
|
||||
async render => {
|
||||
|
||||
+4
-1
@@ -258,7 +258,10 @@ function flattenTopLevelChildren(children: mixed): FlatReactChildren {
|
||||
return [fragmentChildElement];
|
||||
}
|
||||
|
||||
function flattenOptionChildren(children: mixed): string {
|
||||
function flattenOptionChildren(children: mixed): ?string {
|
||||
if (children === undefined || children === null) {
|
||||
return children;
|
||||
}
|
||||
let content = '';
|
||||
// Flatten children and warn if they aren't strings or numbers;
|
||||
// invalid types are ignored.
|
||||
|
||||
Reference in New Issue
Block a user