Skip to content

Commit f630986

Browse files
committed
support FunctionComponent.contextTypes
1 parent 4eaa1c1 commit f630986

2 files changed

Lines changed: 48 additions & 14 deletions

File tree

packages/react-debug-tools/src/ReactDebugHooks.js

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -604,9 +604,10 @@ function processDebugValues(
604604
}
605605

606606
export function inspectHooks<Props>(
607-
renderFunction: Props => React$Node,
607+
renderFunction: (Props, any) => React$Node,
608608
props: Props,
609609
currentDispatcher: ?CurrentDispatcherRef,
610+
legacyContext: any,
610611
): HooksTree {
611612
// DevTools will pass the current renderer's injected dispatcher.
612613
// Other apps might compile debug hooks as part of their app though.
@@ -620,7 +621,7 @@ export function inspectHooks<Props>(
620621
let ancestorStackError;
621622
try {
622623
ancestorStackError = new Error();
623-
renderFunction(props);
624+
renderFunction(props, legacyContext);
624625
} finally {
625626
readHookLog = hookLog;
626627
hookLog = [];
@@ -632,19 +633,36 @@ export function inspectHooks<Props>(
632633

633634
function setupContexts(contextMap: Map<ReactContext<any>, any>, fiber: Fiber) {
634635
let current = fiber;
635-
while (current) {
636-
if (current.tag === ContextProvider) {
637-
const providerType: ReactProviderType<any> = current.type;
638-
const context: ReactContext<any> = providerType._context;
639-
if (!contextMap.has(context)) {
640-
// Store the current value that we're going to restore later.
641-
contextMap.set(context, context._currentValue);
642-
// Set the inner most provider value on the context.
643-
context._currentValue = current.memoizedProps.value;
636+
let legacyContext = null;
637+
if (current.tag === FunctionComponent && current.elementType.contextTypes) {
638+
let childContextTypesFound = false;
639+
while (current !== null && childContextTypesFound === false) {
640+
if (
641+
current.stateNode &&
642+
current.stateNode.__reactInternalMemoizedMergedChildContext
643+
) {
644+
childContextTypesFound = true;
645+
legacyContext =
646+
current.stateNode.__reactInternalMemoizedMergedChildContext;
647+
}
648+
current = current.return;
649+
}
650+
} else {
651+
while (current) {
652+
if (current.tag === ContextProvider) {
653+
const providerType: ReactProviderType<any> = current.type;
654+
const context: ReactContext<any> = providerType._context;
655+
if (!contextMap.has(context)) {
656+
// Store the current value that we're going to restore later.
657+
contextMap.set(context, context._currentValue);
658+
// Set the inner most provider value on the context.
659+
context._currentValue = current.memoizedProps.value;
660+
}
644661
}
662+
current = current.return;
645663
}
646-
current = current.return;
647664
}
665+
return legacyContext;
648666
}
649667

650668
function restoreContexts(contextMap: Map<ReactContext<any>, any>) {
@@ -722,7 +740,7 @@ export function inspectHooksOfFiber(
722740
currentHook = (fiber.memoizedState: Hook);
723741
const contextMap = new Map();
724742
try {
725-
setupContexts(contextMap, fiber);
743+
const legacyContext = setupContexts(contextMap, fiber);
726744
if (fiber.tag === ForwardRef) {
727745
return inspectHooksOfForwardRef(
728746
type.render,
@@ -731,7 +749,7 @@ export function inspectHooksOfFiber(
731749
currentDispatcher,
732750
);
733751
}
734-
return inspectHooks(type, props, currentDispatcher);
752+
return inspectHooks(type, props, currentDispatcher, legacyContext);
735753
} finally {
736754
currentHook = null;
737755
restoreContexts(contextMap);

packages/react-devtools-shared/src/backend/renderer.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2186,6 +2186,22 @@ export function attach(
21862186
if (!shouldHideContext) {
21872187
context = stateNode.context;
21882188
}
2189+
} else {
2190+
// Try to extract legacyContext from stateless components
2191+
// which do not have stateNode
2192+
let current = fiber.return;
2193+
let childContextTypesFound = false;
2194+
while (current !== null && childContextTypesFound === false) {
2195+
if (
2196+
current.stateNode &&
2197+
current.stateNode.__reactInternalMemoizedMergedChildContext
2198+
) {
2199+
childContextTypesFound = true;
2200+
context =
2201+
current.stateNode.__reactInternalMemoizedMergedChildContext;
2202+
}
2203+
current = current.return;
2204+
}
21892205
}
21902206
} else if (
21912207
typeSymbol === CONTEXT_NUMBER ||

0 commit comments

Comments
 (0)