Skip to content

Commit 0ab6817

Browse files
committed
Refactor shouldSetTextContent & add tests (#11789)
1 parent 7c39328 commit 0ab6817

File tree

4 files changed

+53
-11
lines changed

4 files changed

+53
-11
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,16 @@ describe('ReactDOMTextComponent', () => {
197197
expect(el.textContent).toBe('');
198198
});
199199

200+
it('can reconcile text from pre-rendered markup using dangerouslySetInnerHTML and an object with toString', () => {
201+
const HelloObject = {toString: () => 'Hello'};
202+
const el = document.createElement('div');
203+
let reactEl = <p dangerouslySetInnerHTML={{__html: HelloObject}} />;
204+
el.innerHTML = ReactDOMServer.renderToString(reactEl);
205+
206+
ReactDOM.hydrate(reactEl, el);
207+
expect(el.textContent).toBe('Hello');
208+
});
209+
200210
xit('can reconcile text arbitrarily split into multiple nodes', () => {
201211
const el = document.createElement('div');
202212
let inst = ReactDOM.render(

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

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -659,14 +659,36 @@ const DOMRenderer = ReactFiberReconciler({
659659
},
660660

661661
shouldSetTextContent(type: string, props: Props): boolean {
662-
return (
663-
type === 'textarea' ||
662+
if (type === 'textarea') {
663+
return true;
664+
}
665+
666+
if (
664667
typeof props.children === 'string' ||
665-
typeof props.children === 'number' ||
666-
(typeof props.dangerouslySetInnerHTML === 'object' &&
667-
props.dangerouslySetInnerHTML !== null &&
668-
typeof props.dangerouslySetInnerHTML.__html === 'string')
669-
);
668+
typeof props.children === 'number'
669+
) {
670+
return true;
671+
}
672+
673+
if (
674+
typeof props.dangerouslySetInnerHTML === 'object' &&
675+
props.dangerouslySetInnerHTML !== null
676+
) {
677+
if (typeof props.dangerouslySetInnerHTML.__html === 'string') {
678+
return true;
679+
}
680+
681+
// Or allow any type of object through - this is to allow React to render
682+
// the `toString` method of objects. (#11792)
683+
if (
684+
typeof props.dangerouslySetInnerHTML.__html === 'object' &&
685+
props.dangerouslySetInnerHTML.__html !== 'null'
686+
) {
687+
return true;
688+
}
689+
}
690+
691+
return false;
670692
},
671693

672694
shouldDeprioritizeSubtree(type: string, props: Props): boolean {

packages/react-dom/src/client/__tests__/dangerouslySetInnerHTML-test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,14 @@ describe('dangerouslySetInnerHTML', () => {
9191
expect(circle.tagName).toBe('circle');
9292
});
9393
});
94+
95+
it('when rendering an object with a toString method', () => {
96+
const container = document.createElement('div');
97+
const HelloObject = {toString: () => 'Hello'};
98+
const node = ReactDOM.render(
99+
<div dangerouslySetInnerHTML={{__html: HelloObject}} />,
100+
container,
101+
);
102+
expect(node.textContent).toBe('Hello');
103+
});
94104
});

scripts/rollup/results.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,15 @@
4646
"filename": "react-dom.development.js",
4747
"bundleType": "UMD_DEV",
4848
"packageName": "react-dom",
49-
"size": 626353,
50-
"gzip": 144739
49+
"size": 626271,
50+
"gzip": 144757
5151
},
5252
{
5353
"filename": "react-dom.production.min.js",
5454
"bundleType": "UMD_PROD",
5555
"packageName": "react-dom",
56-
"size": 102821,
57-
"gzip": 32649
56+
"size": 102811,
57+
"gzip": 32643
5858
},
5959
{
6060
"filename": "react-dom.development.js",

0 commit comments

Comments
 (0)