diff --git a/src/renderers/dom/fiber/ReactDOMFiberComponent.js b/src/renderers/dom/fiber/ReactDOMFiberComponent.js index a6323f9643994..cb229b9dd56a5 100644 --- a/src/renderers/dom/fiber/ReactDOMFiberComponent.js +++ b/src/renderers/dom/fiber/ReactDOMFiberComponent.js @@ -157,6 +157,14 @@ function ensureListeningTo(rootContainerElement, registrationName) { listenTo(registrationName, doc); } +function getOwnerDocumentFromRootContainer( + rootContainerElement: Element | Document, +): Document { + return rootContainerElement.nodeType === DOCUMENT_NODE + ? (rootContainerElement: any) + : rootContainerElement.ownerDocument; +} + // There are so many media events, it makes sense to just // maintain a list rather than create a `trapBubbledEvent` for each var mediaEvents = { @@ -296,10 +304,9 @@ var ReactDOMFiberComponent = { ): Element { // We create tags in the namespace of their parent container, except HTML // tags get no namespace. - var ownerDocument: Document = rootContainerElement.nodeType === - DOCUMENT_NODE - ? (rootContainerElement: any) - : rootContainerElement.ownerDocument; + var ownerDocument: Document = getOwnerDocumentFromRootContainer( + rootContainerElement, + ); var domElement: Element; var namespaceURI = parentNamespace; if (namespaceURI === HTML_NAMESPACE) { @@ -362,6 +369,12 @@ var ReactDOMFiberComponent = { return domElement; }, + createTextNode(text: string, rootContainerElement: Element | Document): Text { + return getOwnerDocumentFromRootContainer( + rootContainerElement, + ).createTextNode(text); + }, + setInitialProperties( domElement: Element, tag: string, diff --git a/src/renderers/dom/fiber/ReactDOMFiberEntry.js b/src/renderers/dom/fiber/ReactDOMFiberEntry.js index 72781c37f3399..63743b4abebfc 100644 --- a/src/renderers/dom/fiber/ReactDOMFiberEntry.js +++ b/src/renderers/dom/fiber/ReactDOMFiberEntry.js @@ -46,6 +46,7 @@ var invariant = require('fbjs/lib/invariant'); var {getChildNamespace} = DOMNamespaces; var { createElement, + createTextNode, setInitialProperties, diffProperties, updateProperties, @@ -368,7 +369,7 @@ var DOMRenderer = ReactFiberReconciler({ const hostContextDev = ((hostContext: any): HostContextDev); validateDOMNesting(null, text, null, hostContextDev.ancestorInfo); } - var textNode: TextInstance = document.createTextNode(text); + var textNode: TextInstance = createTextNode(text, rootContainerInstance); precacheFiberNode(internalInstanceHandle, textNode); return textNode; }, diff --git a/src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js b/src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js index 4c90d2c65496d..c5e84a56b0fc9 100644 --- a/src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js +++ b/src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js @@ -1117,5 +1117,35 @@ describe('ReactDOMFiber', () => { 'to empty a container.', ); }); + + it('should render a text component with a text DOM node on the same document as the container', () => { + // 1. Create a new document through the use of iframe + // 2. Set up the spy to make asserts when a text component + // is rendered inside the iframe container + var textContent = 'Hello world'; + var iframe = document.createElement('iframe'); + document.body.appendChild(iframe); + var iframeDocument = iframe.contentDocument; + iframeDocument.write( + '
', + ); + iframeDocument.close(); + var iframeContainer = iframeDocument.body.firstChild; + + var actualDocument; + var textNode; + + spyOn(iframeContainer, 'appendChild').and.callFake(node => { + actualDocument = node.ownerDocument; + textNode = node; + }); + + ReactDOM.render(textContent, iframeContainer); + + expect(textNode.textContent).toBe(textContent); + expect(actualDocument).not.toBe(document); + expect(actualDocument).toBe(iframeDocument); + expect(iframeContainer.appendChild).toHaveBeenCalledTimes(1); + }); } });