From 4eaa1c1d16c9ab9dca1cd87c46cdfbe5d0ab952a Mon Sep 17 00:00:00 2001 From: Nick Reiley Date: Thu, 28 May 2020 05:41:52 +0500 Subject: [PATCH 01/15] add fixture to InspectableElements/Contexts.js --- .../src/app/InspectableElements/Contexts.js | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/react-devtools-shell/src/app/InspectableElements/Contexts.js b/packages/react-devtools-shell/src/app/InspectableElements/Contexts.js index 030e995e356c4..ac90457674dd4 100644 --- a/packages/react-devtools-shell/src/app/InspectableElements/Contexts.js +++ b/packages/react-devtools-shell/src/app/InspectableElements/Contexts.js @@ -65,6 +65,14 @@ class LegacyContextConsumer extends Component { } } +function FunctionalLegacyContextConsumer(props, context) { + return context.null; +} + +FunctionalLegacyContextConsumer.contextTypes = { + null: PropTypes.any, +}; + const ModernContext = createContext(); ModernContext.displayName = 'ModernContext'; const ArrayContext = createContext(contextData.array); @@ -92,22 +100,33 @@ class ModernContextType extends Component { } } -function FunctionalContextConsumer() { +function FunctionalModernContextConsumer() { useContext(StringContext); return null; } +function FunctionalLegacyAndModernContextConsumer(props, context) { + useContext(StringContext); + return context.null; +} + +FunctionalLegacyAndModernContextConsumer.contextTypes = { + null: PropTypes.any, +}; + export default function Contexts() { return ( + + {value => null} - + {value => null} {value => null} {value => null} From 33a86ec8410ba8fa90310d58884d5239c3fae6e4 Mon Sep 17 00:00:00 2001 From: Nick Reiley Date: Thu, 28 May 2020 05:43:14 +0500 Subject: [PATCH 02/15] support FunctionComponent.contextTypes --- .../react-debug-tools/src/ReactDebugHooks.js | 46 +++++++++++++------ .../src/backend/renderer.js | 16 +++++++ 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index c9be0d66f7684..ed902d1b2164e 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -604,9 +604,10 @@ function processDebugValues( } export function inspectHooks( - renderFunction: Props => React$Node, + renderFunction: (Props, any) => React$Node, props: Props, currentDispatcher: ?CurrentDispatcherRef, + legacyContext: any, ): HooksTree { // DevTools will pass the current renderer's injected dispatcher. // Other apps might compile debug hooks as part of their app though. @@ -620,7 +621,7 @@ export function inspectHooks( let ancestorStackError; try { ancestorStackError = new Error(); - renderFunction(props); + renderFunction(props, legacyContext); } finally { readHookLog = hookLog; hookLog = []; @@ -632,19 +633,36 @@ export function inspectHooks( function setupContexts(contextMap: Map, any>, fiber: Fiber) { let current = fiber; - while (current) { - if (current.tag === ContextProvider) { - const providerType: ReactProviderType = current.type; - const context: ReactContext = providerType._context; - if (!contextMap.has(context)) { - // Store the current value that we're going to restore later. - contextMap.set(context, context._currentValue); - // Set the inner most provider value on the context. - context._currentValue = current.memoizedProps.value; + let legacyContext = null; + if (current.elementType.contextTypes) { + let childContextFound = false; + while (current !== null && childContextFound === false) { + if ( + current.stateNode && + current.stateNode.__reactInternalMemoizedMergedChildContext + ) { + childContextFound = true; + legacyContext = + current.stateNode.__reactInternalMemoizedMergedChildContext; + } + current = current.return; + } + } else { + while (current) { + if (current.tag === ContextProvider) { + const providerType: ReactProviderType = current.type; + const context: ReactContext = providerType._context; + if (!contextMap.has(context)) { + // Store the current value that we're going to restore later. + contextMap.set(context, context._currentValue); + // Set the inner most provider value on the context. + context._currentValue = current.memoizedProps.value; + } } + current = current.return; } - current = current.return; } + return legacyContext; } function restoreContexts(contextMap: Map, any>) { @@ -722,7 +740,7 @@ export function inspectHooksOfFiber( currentHook = (fiber.memoizedState: Hook); const contextMap = new Map(); try { - setupContexts(contextMap, fiber); + const legacyContext = setupContexts(contextMap, fiber); if (fiber.tag === ForwardRef) { return inspectHooksOfForwardRef( type.render, @@ -731,7 +749,7 @@ export function inspectHooksOfFiber( currentDispatcher, ); } - return inspectHooks(type, props, currentDispatcher); + return inspectHooks(type, props, currentDispatcher, legacyContext); } finally { currentHook = null; restoreContexts(contextMap); diff --git a/packages/react-devtools-shared/src/backend/renderer.js b/packages/react-devtools-shared/src/backend/renderer.js index d39ec771ca60c..060634ecdbdf4 100644 --- a/packages/react-devtools-shared/src/backend/renderer.js +++ b/packages/react-devtools-shared/src/backend/renderer.js @@ -2186,6 +2186,22 @@ export function attach( if (!shouldHideContext) { context = stateNode.context; } + } else { + // Try to extract legacyContext from stateless components + // which do not have stateNode + let current = fiber.return; + let childContextFound = false; + while (current !== null && childContextFound === false) { + if ( + current.stateNode && + current.stateNode.__reactInternalMemoizedMergedChildContext + ) { + childContextFound = true; + context = + current.stateNode.__reactInternalMemoizedMergedChildContext; + } + current = current.return; + } } } else if ( typeSymbol === CONTEXT_NUMBER || From 51b3c89e59bafeb82045c454c229ae330ae86aa1 Mon Sep 17 00:00:00 2001 From: Nick Reiley Date: Thu, 28 May 2020 06:47:44 +0500 Subject: [PATCH 03/15] fix babel/babel#11216 --- yarn.lock | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 89 insertions(+), 7 deletions(-) diff --git a/yarn.lock b/yarn.lock index 699d6fcff37e9..562943a44e9d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25,7 +25,16 @@ dependencies: "@babel/highlight" "^7.8.3" -"@babel/compat-data@^7.8.0", "@babel/compat-data@^7.8.1": +"@babel/compat-data@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.10.1.tgz#b1085ffe72cd17bf2c0ee790fc09f9626011b2db" + integrity sha512-CHvCj7So7iCkGKPRFUfryXIkU2gSBw7VSZFYLsqVhrS47269VK2Hfi9S/YcublPMW8k1u2bQBlbDruoQEm4fgw== + dependencies: + browserslist "^4.12.0" + invariant "^2.2.4" + semver "^5.5.0" + +"@babel/compat-data@^7.8.0": version "7.8.1" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.8.1.tgz#fc0bbbb7991e4fb2b47e168e60f2cc2c41680be9" integrity sha512-Z+6ZOXvyOWYxJ50BwxzdhRnRsGST8Y3jaZgxYig575lTjVSs3KtJnmESwZegg6e2Dn0td1eDhoWlp1wI4BTCPw== @@ -147,14 +156,14 @@ "@babel/types" "^7.8.3" "@babel/helper-compilation-targets@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.3.tgz#2deedc816fd41dca7355ef39fd40c9ea69f0719a" - integrity sha512-JLylPCsFjhLN+6uBSSh3iYdxKdeO9MNmoY96PE/99d8kyBFaXLORtAVhqN6iHa+wtPeqxKLghDOZry0+Aiw9Tw== + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.1.tgz#ad6f69b4c3bae955081ef914a84e5878ffcaca63" + integrity sha512-YuF8IrgSmX/+MV2plPkjEnzlC2wf+gaok8ehMNN0jodF3/sejZauExqpEVGbJua62oaWoNYIXwz4RmAsVcGyHw== dependencies: - "@babel/compat-data" "^7.8.1" - browserslist "^4.8.2" + "@babel/compat-data" "^7.10.1" + browserslist "^4.12.0" invariant "^2.2.4" - levenary "^1.1.0" + levenary "^1.1.1" semver "^5.5.0" "@babel/helper-create-class-features-plugin@^7.8.3": @@ -3021,6 +3030,16 @@ browserify-zlib@~0.1.4: dependencies: pako "~0.2.0" +browserslist@^4.12.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.12.0.tgz#06c6d5715a1ede6c51fc39ff67fd647f740b656d" + integrity sha512-UH2GkcEDSI0k/lRkuDSzFl9ZZ87skSy9w2XAn1MsZnL+4c4rqbBd3e82UWHbYDpztABrPBhZsTEeuxVfHppqDg== + dependencies: + caniuse-lite "^1.0.30001043" + electron-to-chromium "^1.3.413" + node-releases "^1.1.53" + pkg-up "^2.0.0" + browserslist@^4.8.2, browserslist@^4.8.3: version "4.8.5" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.5.tgz#691af4e327ac877b25e7a3f7ee869c4ef36cdea3" @@ -3264,6 +3283,11 @@ caniuse-lite@^1.0.30001022: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001022.tgz#9eeffe580c3a8f110b7b1742dcf06a395885e4c6" integrity sha512-FjwPPtt/I07KyLPkBQ0g7/XuZg6oUkYBVnPHNj3VHJbOjmmJ/GdSo/GUY6MwINEQvjhP6WZVbX8Tvms8xh0D5A== +caniuse-lite@^1.0.30001043: + version "1.0.30001066" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001066.tgz#0a8a58a10108f2b9bf38e7b65c237b12fd9c5f04" + integrity sha512-Gfj/WAastBtfxLws0RCh2sDbTK/8rJuSeZMecrSkNGYxPcv7EzblmDGfWQCFEQcSqYE2BRgQiJh8HOD07N5hIw== + capture-exit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" @@ -4661,6 +4685,11 @@ electron-to-chromium@^1.3.338: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.340.tgz#5d4fe78e984d4211194cf5a52e08069543da146f" integrity sha512-hRFBAglhcj5iVYH+o8QU0+XId1WGoc0VGowJB1cuJAt3exHGrivZvWeAO5BRgBZqwZtwxjm8a5MQeGoT/Su3ww== +electron-to-chromium@^1.3.413: + version "1.3.453" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.453.tgz#758a8565a64b7889b27132a51d2abb8b135c9d01" + integrity sha512-IQbCfjJR0NDDn/+vojTlq7fPSREcALtF8M1n01gw7nQghCtfFYrJ2dfhsp8APr8bANoFC8vRTFVXMOGpT0eetw== + electron@^5.0.0: version "5.0.9" resolved "https://registry.yarnpkg.com/electron/-/electron-5.0.9.tgz#d7000dcb69b74a85b81cb168e7ffdcac254464e5" @@ -5788,6 +5817,13 @@ find-up@^1.0.0: path-exists "^2.0.0" pinkie-promise "^2.0.0" +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + find-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" @@ -8329,6 +8365,13 @@ levenary@^1.1.0: dependencies: leven "^3.1.0" +levenary@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" + integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== + dependencies: + leven "^3.1.0" + levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -8390,6 +8433,14 @@ local-storage-fallback@^4.1.1: dependencies: cookie "^0.3.1" +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -9335,6 +9386,11 @@ node-releases@^1.1.46: dependencies: semver "^6.3.0" +node-releases@^1.1.53: + version "1.1.57" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.57.tgz#f6754ce225fad0611e61228df3e09232e017ea19" + integrity sha512-ZQmnWS7adi61A9JsllJ2gdj2PauElcjnOwTp2O011iGzoakTxUsDGSe+6vD7wXbKdqhSFymC0OSx35aAMhrSdw== + node-rsa@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/node-rsa/-/node-rsa-1.0.5.tgz#854dc1b275729d69bc25883f83ca80705db9262e" @@ -9757,6 +9813,13 @@ p-is-promise@^2.0.0: resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + p-limit@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -9771,6 +9834,13 @@ p-limit@^2.1.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + p-locate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" @@ -9804,6 +9874,11 @@ p-retry@^3.0.1: dependencies: retry "^0.12.0" +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -10204,6 +10279,13 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" + integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= + dependencies: + find-up "^2.1.0" + plugin-error@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace" From bede31a3bf425a4c787c1c7195e9ccac574b7341 Mon Sep 17 00:00:00 2001 From: Nick Reiley Date: Thu, 28 May 2020 15:40:09 +0500 Subject: [PATCH 04/15] enable up to 17 version --- .../react-debug-tools/src/ReactDebugHooks.js | 11 +++-- .../src/backend/renderer.js | 44 +++++++++++++------ 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index ed902d1b2164e..d9c26fb3d3e5a 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -631,10 +631,14 @@ export function inspectHooks( return buildTree(rootStack, readHookLog); } -function setupContexts(contextMap: Map, any>, fiber: Fiber) { +function setupContexts( + contextMap: Map, any>, + fiber: Fiber, + enableLegacyContext: ?boolean, +) { let current = fiber; let legacyContext = null; - if (current.elementType.contextTypes) { + if (enableLegacyContext && current.elementType.contextTypes) { let childContextFound = false; while (current !== null && childContextFound === false) { if ( @@ -709,6 +713,7 @@ function resolveDefaultProps(Component, baseProps) { export function inspectHooksOfFiber( fiber: Fiber, currentDispatcher: ?CurrentDispatcherRef, + enableLegacyContext: ?boolean, ) { // DevTools will pass the current renderer's injected dispatcher. // Other apps might compile debug hooks as part of their app though. @@ -740,7 +745,7 @@ export function inspectHooksOfFiber( currentHook = (fiber.memoizedState: Hook); const contextMap = new Map(); try { - const legacyContext = setupContexts(contextMap, fiber); + const legacyContext = setupContexts(contextMap, fiber, enableLegacyContext); if (fiber.tag === ForwardRef) { return inspectHooksOfForwardRef( type.render, diff --git a/packages/react-devtools-shared/src/backend/renderer.js b/packages/react-devtools-shared/src/backend/renderer.js index 060634ecdbdf4..19ef22af3a927 100644 --- a/packages/react-devtools-shared/src/backend/renderer.js +++ b/packages/react-devtools-shared/src/backend/renderer.js @@ -111,6 +111,10 @@ type ReactTypeOfSideEffectType = {| Placement: number, |}; +type VersionFlags = {| + enableLegacyContext: boolean, +|}; + // Some environments (e.g. React Native / Hermes) don't support the performace API yet. const getCurrentTime = typeof performance === 'object' && typeof performance.now === 'function' @@ -125,6 +129,7 @@ export function getInternalReactConstants( ReactPriorityLevels: ReactPriorityLevelsType, ReactTypeOfSideEffect: ReactTypeOfSideEffectType, ReactTypeOfWork: WorkTagMap, + versionFlags: VersionFlags, |} { const ReactTypeOfSideEffect: ReactTypeOfSideEffectType = { NoEffect: 0b00, @@ -239,6 +244,14 @@ export function getInternalReactConstants( // End of copied code. // ********************************************************** + let versionFlags: VersionFlags = { + enableLegacyContext: true, + }; + + if (gte(version, '17.0.0')) { + versionFlags['enableLegacyContext'] = false; + } + function getTypeSymbol(type: any): Symbol | number { const symbolOrNumber = typeof type === 'object' && type !== null ? type.$$typeof : type; @@ -368,6 +381,7 @@ export function getInternalReactConstants( ReactPriorityLevels, ReactTypeOfWork, ReactTypeOfSideEffect, + versionFlags, }; } @@ -383,6 +397,7 @@ export function attach( ReactPriorityLevels, ReactTypeOfWork, ReactTypeOfSideEffect, + versionFlags, } = getInternalReactConstants(renderer.version); const {NoEffect, PerformedWork, Placement} = ReactTypeOfSideEffect; const { @@ -2187,20 +2202,22 @@ export function attach( context = stateNode.context; } } else { - // Try to extract legacyContext from stateless components - // which do not have stateNode - let current = fiber.return; - let childContextFound = false; - while (current !== null && childContextFound === false) { - if ( - current.stateNode && - current.stateNode.__reactInternalMemoizedMergedChildContext - ) { - childContextFound = true; - context = - current.stateNode.__reactInternalMemoizedMergedChildContext; + if (versionFlags.enableLegacyContext) { + // Try to extract legacyContext from stateless components + // which do not have stateNode + let current = fiber.return; + let childContextFound = false; + while (current !== null && childContextFound === false) { + if ( + current.stateNode && + current.stateNode.__reactInternalMemoizedMergedChildContext + ) { + childContextFound = true; + context = + current.stateNode.__reactInternalMemoizedMergedChildContext; + } + current = current.return; } - current = current.return; } } } else if ( @@ -2282,6 +2299,7 @@ export function attach( hooks = inspectHooksOfFiber( fiber, (renderer.currentDispatcherRef: any), + versionFlags.enableLegacyContext, ); } finally { // Restore original console functionality. From 882d0dff3967fac3972439ed80e100ab3d45b845 Mon Sep 17 00:00:00 2001 From: Nick Reiley Date: Fri, 29 May 2020 16:27:42 +0500 Subject: [PATCH 05/15] enable contextTypes on FunctionComponent only --- .../react-debug-tools/src/ReactDebugHooks.js | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index d9c26fb3d3e5a..545630ff88b89 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -621,7 +621,11 @@ export function inspectHooks( let ancestorStackError; try { ancestorStackError = new Error(); - renderFunction(props, legacyContext); + if (legacyContext) { + renderFunction(props, legacyContext); + } else { + renderFunction(props); + } } finally { readHookLog = hookLog; hookLog = []; @@ -745,16 +749,25 @@ export function inspectHooksOfFiber( currentHook = (fiber.memoizedState: Hook); const contextMap = new Map(); try { - const legacyContext = setupContexts(contextMap, fiber, enableLegacyContext); - if (fiber.tag === ForwardRef) { + if (fiber.tag === FunctionComponent) { + const legacyContext = setupContexts( + contextMap, + fiber, + enableLegacyContext, + ); + return inspectHooks(type, props, currentDispatcher, legacyContext); + } else if (fiber.tag === ForwardRef) { + setupContexts(contextMap, fiber); return inspectHooksOfForwardRef( type.render, props, fiber.ref, currentDispatcher, ); + } else { + setupContexts(contextMap, fiber); + return inspectHooks(type, props, currentDispatcher); } - return inspectHooks(type, props, currentDispatcher, legacyContext); } finally { currentHook = null; restoreContexts(contextMap); From 16d99cafe5db4a9511962ba52cd67e9a660d52df Mon Sep 17 00:00:00 2001 From: Nick Reiley Date: Fri, 29 May 2020 23:12:27 +0500 Subject: [PATCH 06/15] add check on second block --- .../src/backend/renderer.js | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/renderer.js b/packages/react-devtools-shared/src/backend/renderer.js index 19ef22af3a927..bd1496d0df168 100644 --- a/packages/react-devtools-shared/src/backend/renderer.js +++ b/packages/react-devtools-shared/src/backend/renderer.js @@ -2201,23 +2201,24 @@ export function attach( if (!shouldHideContext) { context = stateNode.context; } - } else { - if (versionFlags.enableLegacyContext) { - // Try to extract legacyContext from stateless components - // which do not have stateNode - let current = fiber.return; - let childContextFound = false; - while (current !== null && childContextFound === false) { - if ( - current.stateNode && - current.stateNode.__reactInternalMemoizedMergedChildContext - ) { - childContextFound = true; - context = - current.stateNode.__reactInternalMemoizedMergedChildContext; - } - current = current.return; + } else if ( + tag === FunctionComponent && + versionFlags.enableLegacyContext + ) { + // Try to extract legacyContext from stateless components + // which do not have stateNode + let current = fiber.return; + let childContextFound = false; + while (current !== null && childContextFound === false) { + if ( + current.stateNode && + current.stateNode.__reactInternalMemoizedMergedChildContext + ) { + childContextFound = true; + context = + current.stateNode.__reactInternalMemoizedMergedChildContext; } + current = current.return; } } } else if ( From edf95a998871789eb021da79b557415ce758d142 Mon Sep 17 00:00:00 2001 From: Nick Reiley Date: Fri, 29 May 2020 23:34:34 +0500 Subject: [PATCH 07/15] do not access context to prevent errors if legacyContext is disabled --- .../src/app/InspectableElements/Contexts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-devtools-shell/src/app/InspectableElements/Contexts.js b/packages/react-devtools-shell/src/app/InspectableElements/Contexts.js index ac90457674dd4..252830675f02b 100644 --- a/packages/react-devtools-shell/src/app/InspectableElements/Contexts.js +++ b/packages/react-devtools-shell/src/app/InspectableElements/Contexts.js @@ -66,7 +66,7 @@ class LegacyContextConsumer extends Component { } function FunctionalLegacyContextConsumer(props, context) { - return context.null; + return null; } FunctionalLegacyContextConsumer.contextTypes = { @@ -107,7 +107,7 @@ function FunctionalModernContextConsumer() { function FunctionalLegacyAndModernContextConsumer(props, context) { useContext(StringContext); - return context.null; + return null; } FunctionalLegacyAndModernContextConsumer.contextTypes = { From fcb10ef82a557e5d38747ad675e353149404da2d Mon Sep 17 00:00:00 2001 From: Nick Reiley Date: Wed, 1 Jul 2020 00:00:16 +0500 Subject: [PATCH 08/15] lint --- packages/react-devtools-shared/src/backend/renderer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/renderer.js b/packages/react-devtools-shared/src/backend/renderer.js index c38356c6c7d91..d13c2f6948f4c 100644 --- a/packages/react-devtools-shared/src/backend/renderer.js +++ b/packages/react-devtools-shared/src/backend/renderer.js @@ -248,12 +248,12 @@ export function getInternalReactConstants( // End of copied code. // ********************************************************** - let versionFlags: VersionFlags = { + const versionFlags: VersionFlags = { enableLegacyContext: true, }; if (gte(version, '17.0.0')) { - versionFlags['enableLegacyContext'] = false; + versionFlags.enableLegacyContext = false; } function getTypeSymbol(type: any): Symbol | number { From 3fd54f0da11b1e78fdf241f68e3567208eee286a Mon Sep 17 00:00:00 2001 From: Nick Reiley Date: Thu, 3 Sep 2020 23:46:06 +0500 Subject: [PATCH 09/15] revert 51b3c89 --- yarn.lock | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/yarn.lock b/yarn.lock index 25209b0876403..1916f50052d8c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8799,13 +8799,6 @@ levenary@^1.1.1: dependencies: leven "^3.1.0" -levenary@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" - integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== - dependencies: - leven "^3.1.0" - levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -8879,14 +8872,6 @@ local-storage-fallback@^4.1.1: dependencies: cookie "^0.3.1" -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -10216,13 +10201,6 @@ p-is-promise@^2.0.0, p-is-promise@^2.1.0: resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - p-limit@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -10237,13 +10215,6 @@ p-limit@^2.1.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - p-locate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" @@ -10277,11 +10248,6 @@ p-retry@^3.0.1: dependencies: retry "^0.12.0" -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -10661,13 +10627,6 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" - integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= - dependencies: - find-up "^2.1.0" - plugin-error@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace" From bef507b8880fed8f42669e31aa0a0f6e40b55457 Mon Sep 17 00:00:00 2001 From: Nick Reiley Date: Fri, 4 Sep 2020 23:59:43 +0500 Subject: [PATCH 10/15] retract versionFlags --- .../react-debug-tools/src/ReactDebugHooks.js | 55 ++++++++----------- .../src/backend/renderer.js | 15 ----- 2 files changed, 24 insertions(+), 46 deletions(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index 03738f5e69ce4..23c6fcd5ce456 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -599,42 +599,36 @@ export function inspectHooks( return buildTree(rootStack, readHookLog); } -function setupContexts( - contextMap: Map, any>, - fiber: Fiber, - enableLegacyContext: ?boolean, -) { - let current = fiber; - let legacyContext = null; - if (enableLegacyContext && current.elementType.contextTypes) { - let childContextFound = false; - while (current !== null && childContextFound === false) { - if ( - current.stateNode && - current.stateNode.__reactInternalMemoizedMergedChildContext - ) { - childContextFound = true; - legacyContext = - current.stateNode.__reactInternalMemoizedMergedChildContext; +function getLegacyContext(fiber: Fiber): Object | null { + const hasLegacyContext = !!fiber.elementType.contextTypes; + if (hasLegacyContext) { + let current = fiber; + while (current !== null) { + const instance = current.stateNode; + if (instance && instance.__reactInternalMemoizedMergedChildContext) { + return instance.__reactInternalMemoizedMergedChildContext; } current = current.return; } - } else { - while (current) { - if (current.tag === ContextProvider) { - const providerType: ReactProviderType = current.type; - const context: ReactContext = providerType._context; - if (!contextMap.has(context)) { - // Store the current value that we're going to restore later. - contextMap.set(context, context._currentValue); - // Set the inner most provider value on the context. - context._currentValue = current.memoizedProps.value; - } + } + return null; +} + +function setupContext(contextMap: Map, any>, fiber: Fiber) { + let current = fiber; + while (current) { + if (current.tag === ContextProvider) { + const providerType: ReactProviderType = current.type; + const context: ReactContext = providerType._context; + if (!contextMap.has(context)) { + // Store the current value that we're going to restore later. + contextMap.set(context, context._currentValue); + // Set the inner most provider value on the context. + context._currentValue = current.memoizedProps.value; } - current = current.return; } + current = current.return; } - return legacyContext; } function restoreContexts(contextMap: Map, any>) { @@ -681,7 +675,6 @@ function resolveDefaultProps(Component, baseProps) { export function inspectHooksOfFiber( fiber: Fiber, currentDispatcher: ?CurrentDispatcherRef, - enableLegacyContext: ?boolean, ) { // DevTools will pass the current renderer's injected dispatcher. // Other apps might compile debug hooks as part of their app though. diff --git a/packages/react-devtools-shared/src/backend/renderer.js b/packages/react-devtools-shared/src/backend/renderer.js index fbbd425b856d8..fb7ee34dae820 100644 --- a/packages/react-devtools-shared/src/backend/renderer.js +++ b/packages/react-devtools-shared/src/backend/renderer.js @@ -111,10 +111,6 @@ type ReactTypeOfSideEffectType = {| Placement: number, |}; -type VersionFlags = {| - enableLegacyContext: boolean, -|}; - // Some environments (e.g. React Native / Hermes) don't support the performance API yet. const getCurrentTime = @@ -277,14 +273,6 @@ export function getInternalReactConstants( // End of copied code. // ********************************************************** - const versionFlags: VersionFlags = { - enableLegacyContext: true, - }; - - if (gte(version, '17.0.0')) { - versionFlags.enableLegacyContext = false; - } - function getTypeSymbol(type: any): Symbol | number { const symbolOrNumber = typeof type === 'object' && type !== null ? type.$$typeof : type; @@ -414,7 +402,6 @@ export function getInternalReactConstants( ReactPriorityLevels, ReactTypeOfWork, ReactTypeOfSideEffect, - versionFlags, }; } @@ -430,7 +417,6 @@ export function attach( ReactPriorityLevels, ReactTypeOfWork, ReactTypeOfSideEffect, - versionFlags, } = getInternalReactConstants(renderer.version); const {NoEffect, PerformedWork, Placement} = ReactTypeOfSideEffect; const { @@ -2365,7 +2351,6 @@ export function attach( hooks = inspectHooksOfFiber( fiber, (renderer.currentDispatcherRef: any), - versionFlags.enableLegacyContext, ); } finally { // Restore original console functionality. From 96b75d6d9cc069bb82ad2f07210d438ee1c1b281 Mon Sep 17 00:00:00 2001 From: Nick Reiley Date: Sat, 5 Sep 2020 00:00:29 +0500 Subject: [PATCH 11/15] Update packages/react-devtools-shared/src/backend/renderer.js Co-authored-by: Brian Vaughn --- .../src/backend/renderer.js | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/renderer.js b/packages/react-devtools-shared/src/backend/renderer.js index fb7ee34dae820..d7ca721f06977 100644 --- a/packages/react-devtools-shared/src/backend/renderer.js +++ b/packages/react-devtools-shared/src/backend/renderer.js @@ -2252,24 +2252,22 @@ export function attach( if (!shouldHideContext) { context = stateNode.context; } - } else if ( - tag === FunctionComponent && - versionFlags.enableLegacyContext - ) { - // Try to extract legacyContext from stateless components - // which do not have stateNode - let current = fiber.return; - let childContextFound = false; - while (current !== null && childContextFound === false) { - if ( - current.stateNode && - current.stateNode.__reactInternalMemoizedMergedChildContext - ) { - childContextFound = true; - context = - current.stateNode.__reactInternalMemoizedMergedChildContext; + } else if (tag === FunctionComponent) { + const hasLegacyContext = !!fiber.elementType.contextTypes; + if (hasLegacyContext) { + let current = fiber.return; + let childContextFound = false; + while (current !== null && childContextFound === false) { + const instance = current.stateNode; + if ( + instance && + instance.__reactInternalMemoizedMergedChildContext + ) { + childContextFound = true; + context = instance.__reactInternalMemoizedMergedChildContext; + } + current = current.return; } - current = current.return; } } } else if ( From 3b5d73904b47551c408833f0885f375d39ae05ab Mon Sep 17 00:00:00 2001 From: Nick Reiley Date: Sat, 5 Sep 2020 00:00:45 +0500 Subject: [PATCH 12/15] Update packages/react-debug-tools/src/ReactDebugHooks.js Co-authored-by: Brian Vaughn --- packages/react-debug-tools/src/ReactDebugHooks.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index 23c6fcd5ce456..593799ca322c0 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -707,12 +707,14 @@ export function inspectHooksOfFiber( const contextMap = new Map(); try { if (fiber.tag === FunctionComponent) { - const legacyContext = setupContexts( - contextMap, - fiber, - enableLegacyContext, - ); - return inspectHooks(type, props, currentDispatcher, legacyContext); + const hasLegacyContext = !!fiber.elementType.contextTypes; + if (hasLegacyContext) { + const legacyContext = getLegacyContext(fiber); + return inspectHooks(type, props, currentDispatcher, legacyContext); + } else { + setupContext(contextMap, fiber); + return inspectHooks(type, props, currentDispatcher); + } } else if (fiber.tag === ForwardRef) { setupContexts(contextMap, fiber); return inspectHooksOfForwardRef( From 87339c3e061dcfbfc8987bb6bfb7834fed6aff0f Mon Sep 17 00:00:00 2001 From: Nick Reiley Date: Sat, 5 Sep 2020 00:19:35 +0500 Subject: [PATCH 13/15] fix --- packages/react-debug-tools/src/ReactDebugHooks.js | 4 ++-- packages/react-devtools-shared/src/backend/renderer.js | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index 593799ca322c0..ad09e553eb077 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -716,7 +716,7 @@ export function inspectHooksOfFiber( return inspectHooks(type, props, currentDispatcher); } } else if (fiber.tag === ForwardRef) { - setupContexts(contextMap, fiber); + setupContext(contextMap, fiber); return inspectHooksOfForwardRef( type.render, props, @@ -724,7 +724,7 @@ export function inspectHooksOfFiber( currentDispatcher, ); } else { - setupContexts(contextMap, fiber); + setupContext(contextMap, fiber); return inspectHooks(type, props, currentDispatcher); } } finally { diff --git a/packages/react-devtools-shared/src/backend/renderer.js b/packages/react-devtools-shared/src/backend/renderer.js index d7ca721f06977..8cd9d8e0b0477 100644 --- a/packages/react-devtools-shared/src/backend/renderer.js +++ b/packages/react-devtools-shared/src/backend/renderer.js @@ -126,7 +126,6 @@ export function getInternalReactConstants( ReactPriorityLevels: ReactPriorityLevelsType, ReactTypeOfSideEffect: ReactTypeOfSideEffectType, ReactTypeOfWork: WorkTagMap, - versionFlags: VersionFlags, |} { const ReactTypeOfSideEffect: ReactTypeOfSideEffectType = { NoEffect: 0b00, From bc8cdddc32683f6946ac27f8a5e8c522b744c39a Mon Sep 17 00:00:00 2001 From: Nick Reiley Date: Sat, 5 Sep 2020 03:08:41 +0500 Subject: [PATCH 14/15] add test --- .../ReactHooksInspectionIntegration-test.js | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js index 01461dfc1648e..b4c572fa2778f 100644 --- a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js +++ b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js @@ -11,6 +11,7 @@ 'use strict'; let React; +let PropTypes; let ReactTestRenderer; let Scheduler; let ReactDebugTools; @@ -20,6 +21,7 @@ describe('ReactHooksInspectionIntegration', () => { beforeEach(() => { jest.resetModules(); React = require('react'); + PropTypes = require('prop-types'); ReactTestRenderer = require('react-test-renderer'); Scheduler = require('scheduler'); act = ReactTestRenderer.act; @@ -335,6 +337,46 @@ describe('ReactHooksInspectionIntegration', () => { ]); }); + it('should inject legacy context which is not a hook', () => { + class LegacyContextProvider extends React.Component { + static childContextTypes = { + string: PropTypes.string, + }; + + getChildContext() { + return { + string: 'abc', + }; + } + + render() { + return this.props.children; + } + } + + function FunctionalLegacyContextConsumer(props, context) { + return
{context.string}
; + } + FunctionalLegacyContextConsumer.contextTypes = { + string: PropTypes.string, + }; + const renderer = ReactTestRenderer.create( + + + , + ); + + const childFiber = renderer.root + .findByType(FunctionalLegacyContextConsumer) + ._currentFiber(); + const hasLegacyContext = !!childFiber.elementType.contextTypes; + if (hasLegacyContext) { + expect(() => + ReactDebugTools.inspectHooksOfFiber(childFiber), + ).not.toThrow(); + } + }); + it('should inspect custom hooks', () => { function useCustom() { const [value] = React.useState('hello'); From 745204bfb07053fece3666d16d84713e8b8ef919 Mon Sep 17 00:00:00 2001 From: Nick Reiley Date: Wed, 9 Sep 2020 01:51:36 +0500 Subject: [PATCH 15/15] update test --- .../ReactHooksInspectionIntegration-test.js | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js index b4c572fa2778f..f82bc6cf04e40 100644 --- a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js +++ b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js @@ -337,44 +337,60 @@ describe('ReactHooksInspectionIntegration', () => { ]); }); - it('should inject legacy context which is not a hook', () => { - class LegacyContextProvider extends React.Component { + it('should be able to access functional legacy context during hook inspection', () => { + let contextValue; + + class FirstLegacyContextProvider extends React.Component { static childContextTypes = { string: PropTypes.string, }; - getChildContext() { return { - string: 'abc', + string: 'valid context', }; } + render() { + return this.props.children; + } + } + class SecondLegacyContextProvider extends React.Component { + static childContextTypes = { + string: PropTypes.string, + }; + getChildContext() { + return { + string: 'invalid context', + }; + } render() { return this.props.children; } } function FunctionalLegacyContextConsumer(props, context) { + contextValue = context.string; return
{context.string}
; } FunctionalLegacyContextConsumer.contextTypes = { string: PropTypes.string, }; + const renderer = ReactTestRenderer.create( - - - , + + +
+ +
+
+
, ); const childFiber = renderer.root .findByType(FunctionalLegacyContextConsumer) ._currentFiber(); - const hasLegacyContext = !!childFiber.elementType.contextTypes; - if (hasLegacyContext) { - expect(() => - ReactDebugTools.inspectHooksOfFiber(childFiber), - ).not.toThrow(); - } + expect(() => ReactDebugTools.inspectHooksOfFiber(childFiber)).not.toThrow(); + expect(contextValue).toBe('valid context'); }); it('should inspect custom hooks', () => {