From 3833659cab063bb18ae44cf0fe4deab932ae9466 Mon Sep 17 00:00:00 2001 From: Ben Alpert Date: Thu, 10 Aug 2017 16:22:03 -0700 Subject: [PATCH] Warn when nesting 15 subtree inside 16 --- .../renderSubtreeIntoContainer-test.js | 24 ++++++++++++++++++ .../shared/fiber/ReactFiberClassComponent.js | 25 +++++++++++++++++++ .../shared/shared/ReactInstanceMap.js | 8 +++--- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/renderers/dom/shared/__tests__/renderSubtreeIntoContainer-test.js b/src/renderers/dom/shared/__tests__/renderSubtreeIntoContainer-test.js index 43ac5cb5b2b5..cca63bffa77f 100644 --- a/src/renderers/dom/shared/__tests__/renderSubtreeIntoContainer-test.js +++ b/src/renderers/dom/shared/__tests__/renderSubtreeIntoContainer-test.js @@ -14,6 +14,7 @@ var React = require('react'); var PropTypes = require('prop-types'); var ReactDOM = require('react-dom'); +var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); var ReactTestUtils = require('react-dom/test-utils'); var renderSubtreeIntoContainer = require('react-dom') .unstable_renderSubtreeIntoContainer; @@ -299,4 +300,27 @@ describe('renderSubtreeIntoContainer', () => { ReactDOM.render(, container); expect(portal2.textContent).toBe('foo'); }); + + if (ReactDOMFeatureFlags.useFiber) { + it('fails gracefully when mixing React 15 and 16', () => { + class C extends React.Component { + render() { + return
; + } + } + const c = ReactDOM.render(, document.createElement('div')); + // React 15 calls this: + // https://github.com/facebook/react/blob/77b71fc3c4/src/renderers/dom/client/ReactMount.js#L478-L479 + expect(() => { + c._reactInternalInstance._processChildContext({}); + }).toThrow( + '_processChildContext is not available in React 16+. This likely ' + + 'means you have multiple copies of React and are attempting to nest ' + + 'a React 15 tree inside a React 16 tree using ' + + "unstable_renderSubtreeIntoContainer, which isn't supported. Try to " + + 'make sure you have only one copy of React (and ideally, switch to ' + + 'ReactDOM.unstable_createPortal).', + ); + }); + } }); diff --git a/src/renderers/shared/fiber/ReactFiberClassComponent.js b/src/renderers/shared/fiber/ReactFiberClassComponent.js index a6cc6880020a..e726cfd56928 100644 --- a/src/renderers/shared/fiber/ReactFiberClassComponent.js +++ b/src/renderers/shared/fiber/ReactFiberClassComponent.js @@ -40,6 +40,7 @@ var getComponentName = require('getComponentName'); var shallowEqual = require('fbjs/lib/shallowEqual'); var invariant = require('fbjs/lib/invariant'); +const fakeInternalInstance = {}; const isArray = Array.isArray; if (__DEV__) { @@ -54,6 +55,27 @@ if (__DEV__) { callback, ); }; + + // This is so gross but it's at least non-critical and can be removed if + // it causes problems. This is meant to give a nicer error message for + // ReactDOM15.unstable_renderSubtreeIntoContainer(reactDOM16Component, + // ...)) which otherwise throws a "_processChildContext is not a function" + // exception. + Object.defineProperty(fakeInternalInstance, '_processChildContext', { + enumerable: false, + value: function() { + invariant( + false, + '_processChildContext is not available in React 16+. This likely ' + + 'means you have multiple copies of React and are attempting to nest ' + + 'a React 15 tree inside a React 16 tree using ' + + "unstable_renderSubtreeIntoContainer, which isn't supported. Try " + + 'to make sure you have only one copy of React (and ideally, switch ' + + 'to ReactDOM.unstable_createPortal).', + ); + }, + }); + Object.freeze(fakeInternalInstance); } module.exports = function( @@ -283,6 +305,9 @@ module.exports = function( workInProgress.stateNode = instance; // The instance needs access to the fiber so that it can schedule updates ReactInstanceMap.set(instance, workInProgress); + if (__DEV__) { + instance._reactInternalInstance = fakeInternalInstance; + } } function constructClassInstance(workInProgress: Fiber, props: any): any { diff --git a/src/renderers/shared/shared/ReactInstanceMap.js b/src/renderers/shared/shared/ReactInstanceMap.js index 495c82c311b6..c26c3c959a16 100644 --- a/src/renderers/shared/shared/ReactInstanceMap.js +++ b/src/renderers/shared/shared/ReactInstanceMap.js @@ -26,19 +26,19 @@ var ReactInstanceMap = { * supported we can rename it. */ remove: function(key) { - key._reactInternalInstance = undefined; + key._reactInternalFiber = undefined; }, get: function(key) { - return key._reactInternalInstance; + return key._reactInternalFiber; }, has: function(key) { - return key._reactInternalInstance !== undefined; + return key._reactInternalFiber !== undefined; }, set: function(key, value) { - key._reactInternalInstance = value; + key._reactInternalFiber = value; }, };