From 4a69a702bed180b517c58ac30e9b0c26dba89ab7 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Wed, 28 Feb 2024 23:20:32 +0100 Subject: [PATCH 1/8] DevTools: Read context values from context dependencies --- .../react-debug-tools/src/ReactDebugHooks.js | 67 ++++++++----------- 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index 446ac8463106b..574f139726730 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -16,6 +16,7 @@ import type { ReactDebugInfo, } from 'shared/ReactTypes'; import type { + ContextDependency, Fiber, Dispatcher as DispatcherType, } from 'react-reconciler/src/ReactInternalTypes'; @@ -26,7 +27,6 @@ import ReactSharedInternals from 'shared/ReactSharedInternals'; import { FunctionComponent, SimpleMemoComponent, - ContextProvider, ForwardRef, } from 'react-reconciler/src/ReactWorkTags'; import { @@ -61,6 +61,10 @@ type Hook = { next: Hook | null, }; +const GetPrimitiveStackCacheContext: ReactContext = ({ + $$typeof: REACT_CONTEXT_TYPE, + _currentValue: null, +}: any); function getPrimitiveStackCache(): Map> { // This initializes a cache of all primitive hooks so that the top // most stack frames added by calling the primitive hook can be removed. @@ -69,7 +73,7 @@ function getPrimitiveStackCache(): Map> { let readHookLog; try { // Use all hooks here to add them to the hook log. - Dispatcher.useContext(({_currentValue: null}: any)); + Dispatcher.useContext(GetPrimitiveStackCacheContext); Dispatcher.useState(null); Dispatcher.useReducer((s: mixed, a: mixed) => s, null); Dispatcher.useRef(null); @@ -105,12 +109,7 @@ function getPrimitiveStackCache(): Map> { } if (typeof Dispatcher.use === 'function') { // This type check is for Flow only. - Dispatcher.use( - ({ - $$typeof: REACT_CONTEXT_TYPE, - _currentValue: null, - }: any), - ); + Dispatcher.use(GetPrimitiveStackCacheContext); Dispatcher.use({ then() {}, status: 'fulfilled', @@ -139,6 +138,7 @@ function getPrimitiveStackCache(): Map> { let currentFiber: null | Fiber = null; let currentHook: null | Hook = null; +let currentContextDependency: null | ContextDependency = null; function nextHook(): null | Hook { const hook = currentHook; @@ -149,8 +149,19 @@ function nextHook(): null | Hook { } function readContext(context: ReactContext): T { + if (context === GetPrimitiveStackCacheContext) { + // This is a read for filling the primitive stack cache. + // There's no sensible value to return. + return (null: any); + } + if (currentContextDependency === null) { + return context._currentValue; + } // For now we don't expose readContext usage in the hooks debugging info. - return context._currentValue; + const value = ((currentContextDependency.memoizedValue: any): T); + currentContextDependency = currentContextDependency.next; + + return value; } const SuspenseException: mixed = new Error( @@ -218,14 +229,15 @@ function use(usable: Usable): T { } function useContext(context: ReactContext): T { + const value = readContext(context); hookLog.push({ displayName: context.displayName || null, primitive: 'Context', stackError: new Error(), - value: context._currentValue, + value: value, debugInfo: null, }); - return context._currentValue; + return value; } function useState( @@ -992,30 +1004,6 @@ export function inspectHooks( return buildTree(rootStack, readHookLog); } -function setupContexts(contextMap: Map, any>, fiber: Fiber) { - let current: null | Fiber = fiber; - while (current) { - if (current.tag === ContextProvider) { - let context: ReactContext = current.type; - if ((context: any)._context !== undefined) { - // Support inspection of pre-19+ providers. - context = (context: any)._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; - } -} - -function restoreContexts(contextMap: Map, any>) { - contextMap.forEach((value, context) => (context._currentValue = value)); -} - function inspectHooksOfForwardRef( renderFunction: (Props, Ref) => React$Node, props: Props, @@ -1082,6 +1070,9 @@ export function inspectHooksOfFiber( // current state from them. currentHook = (fiber.memoizedState: Hook); currentFiber = fiber; + const dependencies = currentFiber.dependencies; + currentContextDependency = + dependencies !== null ? dependencies.firstContext : null; const type = fiber.type; let props = fiber.memoizedProps; @@ -1089,10 +1080,7 @@ export function inspectHooksOfFiber( props = resolveDefaultProps(type, props); } - const contextMap = new Map, any>(); try { - setupContexts(contextMap, fiber); - if (fiber.tag === ForwardRef) { return inspectHooksOfForwardRef( type.render, @@ -1106,7 +1094,6 @@ export function inspectHooksOfFiber( } finally { currentFiber = null; currentHook = null; - - restoreContexts(contextMap); + currentContextDependency = null; } } From e9eaac1e9926831a2220f5a5bbeead9ef019bfff Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Thu, 29 Feb 2024 01:18:15 +0100 Subject: [PATCH 2/8] Make it explicit that reading from context directly is only supported when not having access to the Fiber tree --- packages/react-debug-tools/src/ReactDebugHooks.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index 574f139726730..285523c070a08 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -154,9 +154,16 @@ function readContext(context: ReactContext): T { // There's no sensible value to return. return (null: any); } - if (currentContextDependency === null) { + if (currentFiber === null) { + // Hook inspection without access to the Fiber tree. return context._currentValue; } + if (currentContextDependency === null) { + throw new Error( + 'Context reads do not line up with context dependencies. This is a bug in React.', + ); + } + // For now we don't expose readContext usage in the hooks debugging info. const value = ((currentContextDependency.memoizedValue: any): T); currentContextDependency = currentContextDependency.next; From 2c0bdc85aacd833cfaf3181464b8f9a5b4b6f6a8 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Tue, 5 Mar 2024 10:34:19 +0100 Subject: [PATCH 3/8] Remove special context Neither writing primitive stack cache nor `ReactDebugTools.inspectHooks()` have access to the fiber tree. --- .../react-debug-tools/src/ReactDebugHooks.js | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index 285523c070a08..ed7cef7e8ffb0 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -61,10 +61,6 @@ type Hook = { next: Hook | null, }; -const GetPrimitiveStackCacheContext: ReactContext = ({ - $$typeof: REACT_CONTEXT_TYPE, - _currentValue: null, -}: any); function getPrimitiveStackCache(): Map> { // This initializes a cache of all primitive hooks so that the top // most stack frames added by calling the primitive hook can be removed. @@ -73,7 +69,7 @@ function getPrimitiveStackCache(): Map> { let readHookLog; try { // Use all hooks here to add them to the hook log. - Dispatcher.useContext(GetPrimitiveStackCacheContext); + Dispatcher.useContext(({_currentValue: null}: any)); Dispatcher.useState(null); Dispatcher.useReducer((s: mixed, a: mixed) => s, null); Dispatcher.useRef(null); @@ -109,7 +105,12 @@ function getPrimitiveStackCache(): Map> { } if (typeof Dispatcher.use === 'function') { // This type check is for Flow only. - Dispatcher.use(GetPrimitiveStackCacheContext); + Dispatcher.use( + ({ + $$typeof: REACT_CONTEXT_TYPE, + _currentValue: null, + }: any), + ); Dispatcher.use({ then() {}, status: 'fulfilled', @@ -149,13 +150,9 @@ function nextHook(): null | Hook { } function readContext(context: ReactContext): T { - if (context === GetPrimitiveStackCacheContext) { - // This is a read for filling the primitive stack cache. - // There's no sensible value to return. - return (null: any); - } if (currentFiber === null) { - // Hook inspection without access to the Fiber tree. + // Hook inspection without access to the Fiber tree + // e.g. when filling the primitive stack cache or during `ReactDebugTools.inspectHooks()`. return context._currentValue; } if (currentContextDependency === null) { From 0775186dfd515856059b531fe33e4c3deae15927 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Tue, 5 Mar 2024 10:35:56 +0100 Subject: [PATCH 4/8] if-else --- .../react-debug-tools/src/ReactDebugHooks.js | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index ed7cef7e8ffb0..1a0c34e306d3f 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -152,20 +152,21 @@ function nextHook(): null | Hook { function readContext(context: ReactContext): T { if (currentFiber === null) { // Hook inspection without access to the Fiber tree - // e.g. when filling the primitive stack cache or during `ReactDebugTools.inspectHooks()`. + // e.g. when warming up the primitive stack cache or during `ReactDebugTools.inspectHooks()`. return context._currentValue; - } - if (currentContextDependency === null) { - throw new Error( - 'Context reads do not line up with context dependencies. This is a bug in React.', - ); - } + } else { + if (currentContextDependency === null) { + throw new Error( + 'Context reads do not line up with context dependencies. This is a bug in React.', + ); + } - // For now we don't expose readContext usage in the hooks debugging info. - const value = ((currentContextDependency.memoizedValue: any): T); - currentContextDependency = currentContextDependency.next; + // For now we don't expose readContext usage in the hooks debugging info. + const value = ((currentContextDependency.memoizedValue: any): T); + currentContextDependency = currentContextDependency.next; - return value; + return value; + } } const SuspenseException: mixed = new Error( From 0df1e46cf6fa798c304afcb605faa7879c35c444 Mon Sep 17 00:00:00 2001 From: eps1lon Date: Wed, 13 Mar 2024 14:18:32 +0100 Subject: [PATCH 5/8] Ensure backwards compatibility with older reconciler versions --- .../react-debug-tools/src/ReactDebugHooks.js | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index 1a0c34e306d3f..a73b39d39294d 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -17,6 +17,7 @@ import type { } from 'shared/ReactTypes'; import type { ContextDependency, + Dependencies, Fiber, Dispatcher as DispatcherType, } from 'react-reconciler/src/ReactInternalTypes'; @@ -33,6 +34,7 @@ import { REACT_MEMO_CACHE_SENTINEL, REACT_CONTEXT_TYPE, } from 'shared/ReactSymbols'; +import hasOwnProperty from 'shared/hasOwnProperty'; type CurrentDispatcherRef = typeof ReactSharedInternals.ReactCurrentDispatcher; @@ -157,7 +159,7 @@ function readContext(context: ReactContext): T { } else { if (currentContextDependency === null) { throw new Error( - 'Context reads do not line up with context dependencies. This is a bug in React.', + 'Context reads do not line up with context dependencies. This is a bug in React Debug Tools.', ); } @@ -1075,9 +1077,28 @@ export function inspectHooksOfFiber( // current state from them. currentHook = (fiber.memoizedState: Hook); currentFiber = fiber; - const dependencies = currentFiber.dependencies; - currentContextDependency = - dependencies !== null ? dependencies.firstContext : null; + if (hasOwnProperty.call(currentFiber, 'dependencies')) { + // $FlowFixMe[incompatible-use]: Flow thinks hasOwnProperty might have nulled `currentFiber` + const dependencies = currentFiber.dependencies; + currentContextDependency = + dependencies !== null ? dependencies.firstContext : null; + } else if (hasOwnProperty.call(currentFiber, 'dependencies_old')) { + const dependencies: Dependencies = (currentFiber: any).dependencies_old; + currentContextDependency = + dependencies !== null ? dependencies.firstContext : null; + } else if (hasOwnProperty.call(currentFiber, 'dependencies_new')) { + const dependencies: Dependencies = (currentFiber: any).dependencies_new; + currentContextDependency = + dependencies !== null ? dependencies.firstContext : null; + } else if (hasOwnProperty.call(currentFiber, 'contextDependencies')) { + const contextDependencies = (currentFiber: any).contextDependencies; + currentContextDependency = + contextDependencies !== null ? contextDependencies.first : null; + } else { + throw new Error( + 'Unsupported React version. This is a bug in React Debug Tools.', + ); + } const type = fiber.type; let props = fiber.memoizedProps; From 2f5faa45f34e3deee6db4d59eb931839f0bc1f79 Mon Sep 17 00:00:00 2001 From: eps1lon Date: Wed, 13 Mar 2024 15:59:31 +0100 Subject: [PATCH 6/8] No memoizedValue before React 18 --- .../react-debug-tools/src/ReactDebugHooks.js | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index a73b39d39294d..e8c17d4d695b7 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -28,6 +28,7 @@ import ReactSharedInternals from 'shared/ReactSharedInternals'; import { FunctionComponent, SimpleMemoComponent, + ContextProvider, ForwardRef, } from 'react-reconciler/src/ReactWorkTags'; import { @@ -164,7 +165,13 @@ function readContext(context: ReactContext): T { } // For now we don't expose readContext usage in the hooks debugging info. - const value = ((currentContextDependency.memoizedValue: any): T); + const value = hasOwnProperty.call(currentContextDependency, 'memoizedValue') + ? // $FlowFixMe[incompatible-use] Flow thinks `hasOwnProperty` mutates `currentContextDependency` + ((currentContextDependency.memoizedValue: any): T) + : // Before React 18, we did not have `memoizedValue` so we rely on `setupContexts` in those versions. + // $FlowFixMe[incompatible-use] Flow thinks `hasOwnProperty` mutates `currentContextDependency` + ((currentContextDependency.context._currentValue: any): T); + // $FlowFixMe[incompatible-use] Flow thinks `hasOwnProperty` mutates `currentContextDependency` currentContextDependency = currentContextDependency.next; return value; @@ -1011,6 +1018,30 @@ export function inspectHooks( return buildTree(rootStack, readHookLog); } +function setupContexts(contextMap: Map, any>, fiber: Fiber) { + let current: null | Fiber = fiber; + while (current) { + if (current.tag === ContextProvider) { + let context: ReactContext = current.type; + if ((context: any)._context !== undefined) { + // Support inspection of pre-19+ providers. + context = (context: any)._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; + } +} + +function restoreContexts(contextMap: Map, any>) { + contextMap.forEach((value, context) => (context._currentValue = value)); +} + function inspectHooksOfForwardRef( renderFunction: (Props, Ref) => React$Node, props: Props, @@ -1077,6 +1108,9 @@ export function inspectHooksOfFiber( // current state from them. currentHook = (fiber.memoizedState: Hook); currentFiber = fiber; + + // Only used for versions of React without memoized context value in context dependencies. + const contextMap = new Map, any>(); if (hasOwnProperty.call(currentFiber, 'dependencies')) { // $FlowFixMe[incompatible-use]: Flow thinks hasOwnProperty might have nulled `currentFiber` const dependencies = currentFiber.dependencies; @@ -1086,14 +1120,17 @@ export function inspectHooksOfFiber( const dependencies: Dependencies = (currentFiber: any).dependencies_old; currentContextDependency = dependencies !== null ? dependencies.firstContext : null; + setupContexts(contextMap, fiber); } else if (hasOwnProperty.call(currentFiber, 'dependencies_new')) { const dependencies: Dependencies = (currentFiber: any).dependencies_new; currentContextDependency = dependencies !== null ? dependencies.firstContext : null; + setupContexts(contextMap, fiber); } else if (hasOwnProperty.call(currentFiber, 'contextDependencies')) { const contextDependencies = (currentFiber: any).contextDependencies; currentContextDependency = contextDependencies !== null ? contextDependencies.first : null; + setupContexts(contextMap, fiber); } else { throw new Error( 'Unsupported React version. This is a bug in React Debug Tools.', @@ -1121,5 +1158,7 @@ export function inspectHooksOfFiber( currentFiber = null; currentHook = null; currentContextDependency = null; + + restoreContexts(contextMap); } } From 4c2a4353400daa907b9eeed6878df7b43499a3cb Mon Sep 17 00:00:00 2001 From: eps1lon Date: Wed, 13 Mar 2024 16:24:37 +0100 Subject: [PATCH 7/8] Keep old control flow --- .../react-debug-tools/src/ReactDebugHooks.js | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index e8c17d4d695b7..1c74dfdd2fd5f 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -1109,41 +1109,41 @@ export function inspectHooksOfFiber( currentHook = (fiber.memoizedState: Hook); currentFiber = fiber; - // Only used for versions of React without memoized context value in context dependencies. - const contextMap = new Map, any>(); - if (hasOwnProperty.call(currentFiber, 'dependencies')) { - // $FlowFixMe[incompatible-use]: Flow thinks hasOwnProperty might have nulled `currentFiber` - const dependencies = currentFiber.dependencies; - currentContextDependency = - dependencies !== null ? dependencies.firstContext : null; - } else if (hasOwnProperty.call(currentFiber, 'dependencies_old')) { - const dependencies: Dependencies = (currentFiber: any).dependencies_old; - currentContextDependency = - dependencies !== null ? dependencies.firstContext : null; - setupContexts(contextMap, fiber); - } else if (hasOwnProperty.call(currentFiber, 'dependencies_new')) { - const dependencies: Dependencies = (currentFiber: any).dependencies_new; - currentContextDependency = - dependencies !== null ? dependencies.firstContext : null; - setupContexts(contextMap, fiber); - } else if (hasOwnProperty.call(currentFiber, 'contextDependencies')) { - const contextDependencies = (currentFiber: any).contextDependencies; - currentContextDependency = - contextDependencies !== null ? contextDependencies.first : null; - setupContexts(contextMap, fiber); - } else { - throw new Error( - 'Unsupported React version. This is a bug in React Debug Tools.', - ); - } - const type = fiber.type; let props = fiber.memoizedProps; if (type !== fiber.elementType) { props = resolveDefaultProps(type, props); } + // Only used for versions of React without memoized context value in context dependencies. + const contextMap = new Map, any>(); try { + if (hasOwnProperty.call(currentFiber, 'dependencies')) { + // $FlowFixMe[incompatible-use]: Flow thinks hasOwnProperty might have nulled `currentFiber` + const dependencies = currentFiber.dependencies; + currentContextDependency = + dependencies !== null ? dependencies.firstContext : null; + } else if (hasOwnProperty.call(currentFiber, 'dependencies_old')) { + const dependencies: Dependencies = (currentFiber: any).dependencies_old; + currentContextDependency = + dependencies !== null ? dependencies.firstContext : null; + setupContexts(contextMap, fiber); + } else if (hasOwnProperty.call(currentFiber, 'dependencies_new')) { + const dependencies: Dependencies = (currentFiber: any).dependencies_new; + currentContextDependency = + dependencies !== null ? dependencies.firstContext : null; + setupContexts(contextMap, fiber); + } else if (hasOwnProperty.call(currentFiber, 'contextDependencies')) { + const contextDependencies = (currentFiber: any).contextDependencies; + currentContextDependency = + contextDependencies !== null ? contextDependencies.first : null; + setupContexts(contextMap, fiber); + } else { + throw new Error( + 'Unsupported React version. This is a bug in React Debug Tools.', + ); + } + if (fiber.tag === ForwardRef) { return inspectHooksOfForwardRef( type.render, From 088fb2c84b1e39d3eb40f84c0de2015f880cda55 Mon Sep 17 00:00:00 2001 From: eps1lon Date: Wed, 13 Mar 2024 16:54:21 +0100 Subject: [PATCH 8/8] Not all versions of `fiber.dependencies` have `contextDependency.memoizedValue` I considered polyfilling `memoizedValue` but it seems safer to call this out when we read the context value. And also to avoid deopts due to using expando properties on the ContextDependency type in old versions. --- .../react-debug-tools/src/ReactDebugHooks.js | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index 1c74dfdd2fd5f..080c3118d7901 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -1109,6 +1109,29 @@ export function inspectHooksOfFiber( currentHook = (fiber.memoizedState: Hook); currentFiber = fiber; + if (hasOwnProperty.call(currentFiber, 'dependencies')) { + // $FlowFixMe[incompatible-use]: Flow thinks hasOwnProperty might have nulled `currentFiber` + const dependencies = currentFiber.dependencies; + currentContextDependency = + dependencies !== null ? dependencies.firstContext : null; + } else if (hasOwnProperty.call(currentFiber, 'dependencies_old')) { + const dependencies: Dependencies = (currentFiber: any).dependencies_old; + currentContextDependency = + dependencies !== null ? dependencies.firstContext : null; + } else if (hasOwnProperty.call(currentFiber, 'dependencies_new')) { + const dependencies: Dependencies = (currentFiber: any).dependencies_new; + currentContextDependency = + dependencies !== null ? dependencies.firstContext : null; + } else if (hasOwnProperty.call(currentFiber, 'contextDependencies')) { + const contextDependencies = (currentFiber: any).contextDependencies; + currentContextDependency = + contextDependencies !== null ? contextDependencies.first : null; + } else { + throw new Error( + 'Unsupported React version. This is a bug in React Debug Tools.', + ); + } + const type = fiber.type; let props = fiber.memoizedProps; if (type !== fiber.elementType) { @@ -1118,30 +1141,11 @@ export function inspectHooksOfFiber( // Only used for versions of React without memoized context value in context dependencies. const contextMap = new Map, any>(); try { - if (hasOwnProperty.call(currentFiber, 'dependencies')) { - // $FlowFixMe[incompatible-use]: Flow thinks hasOwnProperty might have nulled `currentFiber` - const dependencies = currentFiber.dependencies; - currentContextDependency = - dependencies !== null ? dependencies.firstContext : null; - } else if (hasOwnProperty.call(currentFiber, 'dependencies_old')) { - const dependencies: Dependencies = (currentFiber: any).dependencies_old; - currentContextDependency = - dependencies !== null ? dependencies.firstContext : null; - setupContexts(contextMap, fiber); - } else if (hasOwnProperty.call(currentFiber, 'dependencies_new')) { - const dependencies: Dependencies = (currentFiber: any).dependencies_new; - currentContextDependency = - dependencies !== null ? dependencies.firstContext : null; - setupContexts(contextMap, fiber); - } else if (hasOwnProperty.call(currentFiber, 'contextDependencies')) { - const contextDependencies = (currentFiber: any).contextDependencies; - currentContextDependency = - contextDependencies !== null ? contextDependencies.first : null; + if ( + currentContextDependency !== null && + !hasOwnProperty.call(currentContextDependency, 'memoizedValue') + ) { setupContexts(contextMap, fiber); - } else { - throw new Error( - 'Unsupported React version. This is a bug in React Debug Tools.', - ); } if (fiber.tag === ForwardRef) {