Skip to content

Commit ad61a59

Browse files
committed
Flatten ReactSharedInternals
1 parent e63918d commit ad61a59

File tree

56 files changed

+602
-716
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+602
-716
lines changed

packages/react-cache/src/ReactCacheOld.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,11 @@ const Pending = 0;
4444
const Resolved = 1;
4545
const Rejected = 2;
4646

47-
const ReactCurrentDispatcher =
48-
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
49-
.ReactCurrentDispatcher;
47+
const SharedInternals =
48+
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
5049

5150
function readContext(Context: ReactContext<mixed>) {
52-
const dispatcher = ReactCurrentDispatcher.current;
51+
const dispatcher = SharedInternals.H;
5352
if (dispatcher === null) {
5453
// This wasn't being minified but we're going to retire this package anyway.
5554
// eslint-disable-next-line react-internal/prod-error-codes

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

+9-9
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import {
3737
} from 'shared/ReactSymbols';
3838
import hasOwnProperty from 'shared/hasOwnProperty';
3939

40-
type CurrentDispatcherRef = typeof ReactSharedInternals.ReactCurrentDispatcher;
40+
type CurrentDispatcherRef = typeof ReactSharedInternals;
4141

4242
// Used to track hooks called during a render
4343

@@ -1075,11 +1075,11 @@ export function inspectHooks<Props>(
10751075
// DevTools will pass the current renderer's injected dispatcher.
10761076
// Other apps might compile debug hooks as part of their app though.
10771077
if (currentDispatcher == null) {
1078-
currentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
1078+
currentDispatcher = ReactSharedInternals;
10791079
}
10801080

1081-
const previousDispatcher = currentDispatcher.current;
1082-
currentDispatcher.current = DispatcherProxy;
1081+
const previousDispatcher = currentDispatcher.H;
1082+
currentDispatcher.H = DispatcherProxy;
10831083

10841084
let readHookLog;
10851085
let ancestorStackError;
@@ -1093,7 +1093,7 @@ export function inspectHooks<Props>(
10931093
readHookLog = hookLog;
10941094
hookLog = [];
10951095
// $FlowFixMe[incompatible-use] found when upgrading Flow
1096-
currentDispatcher.current = previousDispatcher;
1096+
currentDispatcher.H = previousDispatcher;
10971097
}
10981098
const rootStack = ErrorStackParser.parse(ancestorStackError);
10991099
return buildTree(rootStack, readHookLog);
@@ -1129,9 +1129,9 @@ function inspectHooksOfForwardRef<Props, Ref>(
11291129
ref: Ref,
11301130
currentDispatcher: CurrentDispatcherRef,
11311131
): HooksTree {
1132-
const previousDispatcher = currentDispatcher.current;
1132+
const previousDispatcher = currentDispatcher.H;
11331133
let readHookLog;
1134-
currentDispatcher.current = DispatcherProxy;
1134+
currentDispatcher.H = DispatcherProxy;
11351135
let ancestorStackError;
11361136
try {
11371137
ancestorStackError = new Error();
@@ -1141,7 +1141,7 @@ function inspectHooksOfForwardRef<Props, Ref>(
11411141
} finally {
11421142
readHookLog = hookLog;
11431143
hookLog = [];
1144-
currentDispatcher.current = previousDispatcher;
1144+
currentDispatcher.H = previousDispatcher;
11451145
}
11461146
const rootStack = ErrorStackParser.parse(ancestorStackError);
11471147
return buildTree(rootStack, readHookLog);
@@ -1169,7 +1169,7 @@ export function inspectHooksOfFiber(
11691169
// DevTools will pass the current renderer's injected dispatcher.
11701170
// Other apps might compile debug hooks as part of their app though.
11711171
if (currentDispatcher == null) {
1172-
currentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
1172+
currentDispatcher = ReactSharedInternals;
11731173
}
11741174

11751175
if (

packages/react-debug-tools/src/__tests__/ReactHooksInspection-test.js

-33
Original file line numberDiff line numberDiff line change
@@ -453,39 +453,6 @@ describe('ReactHooksInspection', () => {
453453
`);
454454
});
455455

456-
it('should support an injected dispatcher', () => {
457-
const initial = {
458-
useState() {
459-
throw new Error("Should've been proxied");
460-
},
461-
};
462-
let current = initial;
463-
let getterCalls = 0;
464-
const setterCalls = [];
465-
const FakeDispatcherRef = {
466-
get current() {
467-
getterCalls++;
468-
return current;
469-
},
470-
set current(value) {
471-
setterCalls.push(value);
472-
current = value;
473-
},
474-
};
475-
476-
function Foo(props) {
477-
const [state] = FakeDispatcherRef.current.useState('hello world');
478-
return <div>{state}</div>;
479-
}
480-
481-
ReactDebugTools.inspectHooks(Foo, {}, FakeDispatcherRef);
482-
483-
expect(getterCalls).toBe(2);
484-
expect(setterCalls).toHaveLength(2);
485-
expect(setterCalls[0]).not.toBe(initial);
486-
expect(setterCalls[1]).toBe(initial);
487-
});
488-
489456
it('should inspect use() calls for Promise and Context', async () => {
490457
const MyContext = React.createContext('hi');
491458
const promise = Promise.resolve('world');

packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js

-55
Original file line numberDiff line numberDiff line change
@@ -2345,61 +2345,6 @@ describe('ReactHooksInspectionIntegration', () => {
23452345
`);
23462346
});
23472347

2348-
it('should support an injected dispatcher', async () => {
2349-
function Foo(props) {
2350-
const [state] = React.useState('hello world');
2351-
return <div>{state}</div>;
2352-
}
2353-
2354-
const initial = {};
2355-
let current = initial;
2356-
let getterCalls = 0;
2357-
const setterCalls = [];
2358-
const FakeDispatcherRef = {
2359-
get current() {
2360-
getterCalls++;
2361-
return current;
2362-
},
2363-
set current(value) {
2364-
setterCalls.push(value);
2365-
current = value;
2366-
},
2367-
};
2368-
2369-
let renderer;
2370-
await act(() => {
2371-
renderer = ReactTestRenderer.create(<Foo />, {
2372-
unstable_isConcurrent: true,
2373-
});
2374-
});
2375-
const childFiber = renderer.root._currentFiber();
2376-
2377-
let didCatch = false;
2378-
2379-
try {
2380-
ReactDebugTools.inspectHooksOfFiber(childFiber, FakeDispatcherRef);
2381-
} catch (error) {
2382-
expect(error.message).toBe('Error rendering inspected component');
2383-
expect(error.cause).toBeInstanceOf(Error);
2384-
expect(error.cause.message).toBe(
2385-
'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' +
2386-
' one of the following reasons:\n' +
2387-
'1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +
2388-
'2. You might be breaking the Rules of Hooks\n' +
2389-
'3. You might have more than one copy of React in the same app\n' +
2390-
'See https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.',
2391-
);
2392-
didCatch = true;
2393-
}
2394-
// avoid false positive if no error was thrown at all
2395-
expect(didCatch).toBe(true);
2396-
2397-
expect(getterCalls).toBe(1);
2398-
expect(setterCalls).toHaveLength(2);
2399-
expect(setterCalls[0]).not.toBe(initial);
2400-
expect(setterCalls[1]).toBe(initial);
2401-
});
2402-
24032348
// This test case is based on an open source bug report:
24042349
// https://github.com/facebookincubator/redux-react-hook/issues/34#issuecomment-466693787
24052350
it('should properly advance the current hook for useContext', async () => {

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ export function describeNativeComponentFrame(
8686
// Note that unlike the code this was forked from (in ReactComponentStackFrame)
8787
// DevTools should override the dispatcher even when DevTools is compiled in production mode,
8888
// because the app itself may be in development mode and log errors/warnings.
89-
const previousDispatcher = currentDispatcherRef.current;
90-
currentDispatcherRef.current = null;
89+
const previousDispatcher = currentDispatcherRef.H;
90+
currentDispatcherRef.H = null;
9191
disableLogs();
9292

9393
// NOTE: keep in sync with the implementation in ReactComponentStackFrame
@@ -270,7 +270,7 @@ export function describeNativeComponentFrame(
270270

271271
Error.prepareStackTrace = previousPrepareStackTrace;
272272

273-
currentDispatcherRef.current = previousDispatcher;
273+
currentDispatcherRef.H = previousDispatcher;
274274
reenableLogs();
275275
}
276276
// Fallback to just using the name if we couldn't make it throw.

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

+7-9
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@
99

1010
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
1111
import type {
12+
LegacyDispatcherRef,
1213
CurrentDispatcherRef,
1314
ReactRenderer,
1415
WorkTagMap,
1516
ConsolePatchSettings,
1617
} from './types';
1718
import {format, formatWithStyles} from './utils';
1819

19-
import {getInternalReactConstants} from './renderer';
20+
import {getInternalReactConstants, getDispatcherRef} from './renderer';
2021
import {getStackByFiberInDevAndProd} from './DevToolsFiberComponentStack';
2122
import {consoleManagedByDevToolsDuringStrictMode} from 'react-devtools-feature-flags';
2223
import {castBool, castBrowserTheme} from '../utils';
@@ -75,7 +76,7 @@ type OnErrorOrWarning = (
7576
const injectedRenderers: Map<
7677
ReactRenderer,
7778
{
78-
currentDispatcherRef: CurrentDispatcherRef,
79+
currentDispatcherRef: LegacyDispatcherRef | CurrentDispatcherRef,
7980
getCurrentFiber: () => Fiber | null,
8081
onErrorOrWarning: ?OnErrorOrWarning,
8182
workTagMap: WorkTagMap,
@@ -215,12 +216,9 @@ export function patch({
215216
// Search for the first renderer that has a current Fiber.
216217
// We don't handle the edge case of stacks for more than one (e.g. interleaved renderers?)
217218
// eslint-disable-next-line no-for-of-loops/no-for-of-loops
218-
for (const {
219-
currentDispatcherRef,
220-
getCurrentFiber,
221-
onErrorOrWarning,
222-
workTagMap,
223-
} of injectedRenderers.values()) {
219+
for (const renderer of injectedRenderers.values()) {
220+
const currentDispatcherRef = getDispatcherRef(renderer);
221+
const {getCurrentFiber, onErrorOrWarning, workTagMap} = renderer;
224222
const current: ?Fiber = getCurrentFiber();
225223
if (current != null) {
226224
try {
@@ -241,7 +239,7 @@ export function patch({
241239
const componentStack = getStackByFiberInDevAndProd(
242240
workTagMap,
243241
current,
244-
currentDispatcherRef,
242+
(currentDispatcherRef: any),
245243
);
246244
if (componentStack !== '') {
247245
if (isStrictModeOverride(args, method)) {

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

+30-6
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ import type {
119119
RendererInterface,
120120
SerializedElement,
121121
WorkTagMap,
122+
CurrentDispatcherRef,
123+
LegacyDispatcherRef,
122124
} from './types';
123125
import type {
124126
ComponentFilter,
@@ -140,6 +142,31 @@ type ReactPriorityLevelsType = {
140142
NoPriority: number,
141143
};
142144

145+
export function getDispatcherRef(renderer: {
146+
+currentDispatcherRef?: LegacyDispatcherRef | CurrentDispatcherRef,
147+
...
148+
}): void | CurrentDispatcherRef {
149+
if (renderer.currentDispatcherRef === undefined) {
150+
return undefined;
151+
}
152+
const injectedRef = renderer.currentDispatcherRef;
153+
if (
154+
typeof injectedRef.H === 'undefined' &&
155+
typeof injectedRef.current !== 'undefined'
156+
) {
157+
// We got a legacy dispatcher injected, let's create a wrapper proxy to translate.
158+
return {
159+
get H() {
160+
return (injectedRef: any).current;
161+
},
162+
set H(value) {
163+
(injectedRef: any).current = value;
164+
},
165+
};
166+
}
167+
return (injectedRef: any);
168+
}
169+
143170
function getFiberFlags(fiber: Fiber): number {
144171
// The name of this field changed from "effectTag" to "flags"
145172
return fiber.flags !== undefined ? fiber.flags : (fiber: any).effectTag;
@@ -694,7 +721,7 @@ export function attach(
694721
getDisplayNameForFiber,
695722
getIsProfiling: () => isProfiling,
696723
getLaneLabelMap,
697-
currentDispatcherRef: renderer.currentDispatcherRef,
724+
currentDispatcherRef: getDispatcherRef(renderer),
698725
workTagMap: ReactTypeOfWork,
699726
reactVersion: version,
700727
});
@@ -3344,10 +3371,7 @@ export function attach(
33443371
}
33453372

33463373
try {
3347-
hooks = inspectHooksOfFiber(
3348-
fiber,
3349-
(renderer.currentDispatcherRef: any),
3350-
);
3374+
hooks = inspectHooksOfFiber(fiber, getDispatcherRef(renderer));
33513375
} finally {
33523376
// Restore original console functionality.
33533377
for (const method in originalConsoleMethods) {
@@ -4571,7 +4595,7 @@ export function attach(
45714595
function getComponentStackForFiber(fiber: Fiber): string | null {
45724596
let componentStack = fiberToComponentStackMap.get(fiber);
45734597
if (componentStack == null) {
4574-
const dispatcherRef = renderer.currentDispatcherRef;
4598+
const dispatcherRef = getDispatcherRef(renderer);
45754599
if (dispatcherRef == null) {
45764600
return null;
45774601
}

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

+7-2
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,12 @@ export type NativeType = Object;
8787
export type RendererID = number;
8888

8989
type Dispatcher = any;
90-
export type CurrentDispatcherRef = {current: null | Dispatcher};
90+
export type LegacyDispatcherRef = {current: null | Dispatcher};
91+
type SharedInternalsSubset = {
92+
H: null | Dispatcher,
93+
...
94+
};
95+
export type CurrentDispatcherRef = SharedInternalsSubset;
9196

9297
export type GetDisplayNameForFiberID = (
9398
id: number,
@@ -155,7 +160,7 @@ export type ReactRenderer = {
155160
scheduleUpdate?: ?(fiber: Object) => void,
156161
setSuspenseHandler?: ?(shouldSuspend: (fiber: Object) => boolean) => void,
157162
// Only injected by React v16.8+ in order to support hooks inspection.
158-
currentDispatcherRef?: CurrentDispatcherRef,
163+
currentDispatcherRef?: LegacyDispatcherRef | CurrentDispatcherRef,
159164
// Only injected by React v16.9+ in DEV mode.
160165
// Enables DevTools to append owners-only component stack to error messages.
161166
getCurrentFiber?: () => Fiber | null,

packages/react-devtools-shared/src/devtools/cache.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,11 @@ const Pending = 0;
5959
const Resolved = 1;
6060
const Rejected = 2;
6161

62-
const ReactCurrentDispatcher = (React: any)
63-
.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher;
62+
const ReactSharedInternals = (React: any)
63+
.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
6464

6565
function readContext(Context: ReactContext<null>) {
66-
const dispatcher = ReactCurrentDispatcher.current;
66+
const dispatcher = ReactSharedInternals.H;
6767
if (dispatcher === null) {
6868
throw new Error(
6969
'react-cache: read and preload may only be called from within a ' +

0 commit comments

Comments
 (0)