@samitouri / QOS-React-2 / commits / 89508f20d4

Make ReactDOM.createPortal() official (#10675)

* Validate portal container early * Add ReactDOM.createPortal but leave unstable_ alias usable

Dan Abramov committed Sep 11, 2017 at 22:23 UTC 89508f20d49cde40d1083f7501fac388b86bbcb8
7 files changed +67 -39
src/renderers/__tests__/ReactUpdates-test.js
+1 -4
@@ -522,10 +522,7 @@ describe('ReactUpdates', () => {
522 var portal = null;
523 // If we're using Fiber, we use Portals instead to achieve this.
524 if (ReactDOMFeatureFlags.useFiber) {
525 - portal = ReactDOM.unstable_createPortal(
526 - <B ref={n => (b = n)} />,
527 - bContainer,
528 - );
525 + portal = ReactDOM.createPortal(<B ref={n => (b = n)} />, bContainer);
526 }
527 return <div>A{this.state.x}{portal}</div>;
528 }
src/renderers/dom/__tests__/ReactDOMProduction-test.js
+1 -4
@@ -246,10 +246,7 @@ describe('ReactDOMProduction', () => {
246 var expectSVG = {ref: el => svgEls.push(el)};
247 var expectHTML = {ref: el => htmlEls.push(el)};
248 var usePortal = function(tree) {
249 - return ReactDOM.unstable_createPortal(
250 - tree,
251 - document.createElement('div'),
252 - );
249 + return ReactDOM.createPortal(tree, document.createElement('div'));
250 };
251 var assertNamespacesMatch = function(tree) {
252 var container = document.createElement('div');
src/renderers/dom/fiber/ReactDOMFiberEntry.js
+18 -8
@@ -646,7 +646,22 @@ function renderSubtreeIntoContainer(
646 return DOMRenderer.getPublicRootInstance(root);
647 }
648
649 +function createPortal(
650 + children: ReactNodeList,
651 + container: DOMContainer,
652 + key: ?string = null,
653 +) {
654 + invariant(
655 + isValidContainer(container),
656 + 'Target container is not a DOM element.',
657 + );
658 + // TODO: pass ReactDOM portal implementation as third argument
659 + return ReactPortal.createPortal(children, container, null, key);
660 +}
661 +
662 var ReactDOMFiber = {
663 + createPortal,
664 +
665 hydrate(element: React$Node, container: DOMContainer, callback: ?Function) {
666 // TODO: throw or warn if we couldn't hydrate?
667 return renderSubtreeIntoContainer(null, element, container, true, callback);
@@ -742,14 +757,9 @@ var ReactDOMFiber = {
757
758 findDOMNode: findDOMNode,
759
745 - unstable_createPortal(
746 - children: ReactNodeList,
747 - container: DOMContainer,
748 - key: ?string = null,
749 - ) {
750 - // TODO: pass ReactDOM portal implementation as third argument
751 - return ReactPortal.createPortal(children, container, null, key);
752 - },
760 + // Temporary alias since we already shipped React 16 RC with it.
761 + // TODO: remove in React 17.
762 + unstable_createPortal: createPortal,
763
764 unstable_batchedUpdates: ReactGenericBatching.batchedUpdates,
765
src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js
+44 -20
@@ -182,10 +182,7 @@ describe('ReactDOMFiber', () => {
182 var expectMath = {ref: el => mathEls.push(el)};
183
184 var usePortal = function(tree) {
185 - return ReactDOM.unstable_createPortal(
186 - tree,
187 - document.createElement('div'),
188 - );
185 + return ReactDOM.createPortal(tree, document.createElement('div'));
186 };
187
188 var assertNamespacesMatch = function(tree) {
@@ -212,6 +209,24 @@ describe('ReactDOMFiber', () => {
209 it('should render one portal', () => {
210 var portalContainer = document.createElement('div');
211
212 + ReactDOM.render(
213 + <div>
214 + {ReactDOM.createPortal(<div>portal</div>, portalContainer)}
215 + </div>,
216 + container,
217 + );
218 + expect(portalContainer.innerHTML).toBe('<div>portal</div>');
219 + expect(container.innerHTML).toBe('<div></div>');
220 +
221 + ReactDOM.unmountComponentAtNode(container);
222 + expect(portalContainer.innerHTML).toBe('');
223 + expect(container.innerHTML).toBe('');
224 + });
225 +
226 + // TODO: remove in React 17
227 + it('should support unstable_createPortal alias', () => {
228 + var portalContainer = document.createElement('div');
229 +
230 ReactDOM.render(
231 <div>
232 {ReactDOM.unstable_createPortal(<div>portal</div>, portalContainer)}
@@ -260,12 +275,12 @@ describe('ReactDOMFiber', () => {
275 const {step} = this.props;
276 return [
277 <Child key="a" name={`normal[0]:${step}`} />,
263 - ReactDOM.unstable_createPortal(
278 + ReactDOM.createPortal(
279 <Child key="b" name={`portal1[0]:${step}`} />,
280 portalContainer1,
281 ),
282 <Child key="c" name={`normal[1]:${step}`} />,
268 - ReactDOM.unstable_createPortal(
283 + ReactDOM.createPortal(
284 [
285 <Child key="d" name={`portal2[0]:${step}`} />,
286 <Child key="e" name={`portal2[1]:${step}`} />,
@@ -334,14 +349,14 @@ describe('ReactDOMFiber', () => {
349 ReactDOM.render(
350 [
351 <div key="a">normal[0]</div>,
337 - ReactDOM.unstable_createPortal(
352 + ReactDOM.createPortal(
353 [
354 <div key="b">portal1[0]</div>,
340 - ReactDOM.unstable_createPortal(
355 + ReactDOM.createPortal(
356 <div key="c">portal2[0]</div>,
357 portalContainer2,
358 ),
344 - ReactDOM.unstable_createPortal(
359 + ReactDOM.createPortal(
360 <div key="d">portal3[0]</div>,
361 portalContainer3,
362 ),
@@ -374,7 +389,7 @@ describe('ReactDOMFiber', () => {
389
390 ReactDOM.render(
391 <div>
377 - {ReactDOM.unstable_createPortal(<div>portal:1</div>, portalContainer)}
392 + {ReactDOM.createPortal(<div>portal:1</div>, portalContainer)}
393 </div>,
394 container,
395 );
@@ -383,7 +398,7 @@ describe('ReactDOMFiber', () => {
398
399 ReactDOM.render(
400 <div>
386 - {ReactDOM.unstable_createPortal(<div>portal:2</div>, portalContainer)}
401 + {ReactDOM.createPortal(<div>portal:2</div>, portalContainer)}
402 </div>,
403 container,
404 );
@@ -392,7 +407,7 @@ describe('ReactDOMFiber', () => {
407
408 ReactDOM.render(
409 <div>
395 - {ReactDOM.unstable_createPortal(<p>portal:3</p>, portalContainer)}
410 + {ReactDOM.createPortal(<p>portal:3</p>, portalContainer)}
411 </div>,
412 container,
413 );
@@ -401,7 +416,7 @@ describe('ReactDOMFiber', () => {
416
417 ReactDOM.render(
418 <div>
404 - {ReactDOM.unstable_createPortal(['Hi', 'Bye'], portalContainer)}
419 + {ReactDOM.createPortal(['Hi', 'Bye'], portalContainer)}
420 </div>,
421 container,
422 );
@@ -410,7 +425,7 @@ describe('ReactDOMFiber', () => {
425
426 ReactDOM.render(
427 <div>
413 - {ReactDOM.unstable_createPortal(['Bye', 'Hi'], portalContainer)}
428 + {ReactDOM.createPortal(['Bye', 'Hi'], portalContainer)}
429 </div>,
430 container,
431 );
@@ -419,7 +434,7 @@ describe('ReactDOMFiber', () => {
434
435 ReactDOM.render(
436 <div>
422 - {ReactDOM.unstable_createPortal(null, portalContainer)}
437 + {ReactDOM.createPortal(null, portalContainer)}
438 </div>,
439 container,
440 );
@@ -700,7 +715,7 @@ describe('ReactDOMFiber', () => {
715 }
716
717 render() {
703 - return ReactDOM.unstable_createPortal(<Component />, portalContainer);
718 + return ReactDOM.createPortal(<Component />, portalContainer);
719 }
720 }
721
@@ -741,7 +756,7 @@ describe('ReactDOMFiber', () => {
756 }
757
758 render() {
744 - return ReactDOM.unstable_createPortal(<Component />, portalContainer);
759 + return ReactDOM.createPortal(<Component />, portalContainer);
760 }
761 }
762
@@ -781,7 +796,7 @@ describe('ReactDOMFiber', () => {
796 }
797
798 render() {
784 - return ReactDOM.unstable_createPortal(<Component />, portalContainer);
799 + return ReactDOM.createPortal(<Component />, portalContainer);
800 }
801 }
802
@@ -821,7 +836,7 @@ describe('ReactDOMFiber', () => {
836
837 ReactDOM.render(
838 <div onClick={() => ops.push('parent clicked')}>
824 - {ReactDOM.unstable_createPortal(
839 + {ReactDOM.createPortal(
840 <div
841 onClick={() => ops.push('portal clicked')}
842 ref={n => (portal = n)}>
@@ -874,7 +889,7 @@ describe('ReactDOMFiber', () => {
889 onMouseEnter={() => ops.push('enter parent')}
890 onMouseLeave={() => ops.push('leave parent')}>
891 <div ref={n => (firstTarget = n)} />
877 - {ReactDOM.unstable_createPortal(
892 + {ReactDOM.createPortal(
893 <div
894 onMouseEnter={() => ops.push('enter portal')}
895 onMouseLeave={() => ops.push('leave portal')}
@@ -909,6 +924,15 @@ describe('ReactDOMFiber', () => {
924 ]);
925 });
926
927 + it('should throw on bad createPortal argument', () => {
928 + expect(() => {
929 + ReactDOM.createPortal(<div>portal</div>, null);
930 + }).toThrow('Target container is not a DOM element.');
931 + expect(() => {
932 + ReactDOM.createPortal(<div>portal</div>, document.createTextNode('hi'));
933 + }).toThrow('Target container is not a DOM element.');
934 + });
935 +
936 it('should warn for non-functional event listeners', () => {
937 spyOn(console, 'error');
938 class Example extends React.Component {
src/renderers/dom/shared/__tests__/renderSubtreeIntoContainer-test.js
+1 -1
@@ -319,7 +319,7 @@ describe('renderSubtreeIntoContainer', () => {
319 'a React 15 tree inside a React 16 tree using ' +
320 "unstable_renderSubtreeIntoContainer, which isn't supported. Try to " +
321 'make sure you have only one copy of React (and ideally, switch to ' +
322 - 'ReactDOM.unstable_createPortal).',
322 + 'ReactDOM.createPortal).',
323 );
324 });
325 }
src/renderers/native/ReactNativeFiberEntry.js
+1 -1
@@ -79,7 +79,7 @@ const ReactNativeFiber: ReactNativeType = {
79 UIManager.removeRootView(containerTag);
80 },
81
82 - unstable_createPortal(
82 + createPortal(
83 children: ReactNodeList,
84 containerTag: number,
85 key: ?string = null,
src/renderers/shared/fiber/ReactFiberClassComponent.js
+1 -1
@@ -71,7 +71,7 @@ if (__DEV__) {
71 'a React 15 tree inside a React 16 tree using ' +
72 "unstable_renderSubtreeIntoContainer, which isn't supported. Try " +
73 'to make sure you have only one copy of React (and ideally, switch ' +
74 - 'to ReactDOM.unstable_createPortal).',
74 + 'to ReactDOM.createPortal).',
75 );
76 },
77 });