Undo dependency injection of batching (#26389)
There's currently a giant cycle between the event system, through react-dom-bindings, reconciler and then react-dom. We resolve this cycle using dependency injection. However, this all ends up in the same bundle. It can be reordered to resolve the cycles. If we avoid side-effects and avoid reading from module exports during initialization, this should be resolvable in a more optimal way by the compiler.
Sebastian Markbåge committed
Mar 14, 2023 at 21:40 UTC
a57f40d839bf055f910cc20d7e501a10df92db98
5 files changed
+25
-112
packages/react-dom-bindings/src/events/ReactDOMControlledComponent.js
+7
-15
@@ -12,9 +12,10 @@ import {
12
getFiberCurrentPropsFromNode,
13
} from '../client/ReactDOMComponentTree';
14
15
+import {restoreControlledState} from 'react-dom-bindings/src/client/ReactDOMComponent';
16
+
17
// Use to restore controlled state after a change event has fired.
18
17
-let restoreImpl = null;
19
let restoreTarget = null;
20
let restoreQueue = null;
21
@@ -27,27 +28,18 @@ function restoreStateOfTarget(target: Node) {
28
return;
29
}
30
30
- if (typeof restoreImpl !== 'function') {
31
- throw new Error(
32
- 'setRestoreImplementation() needs to be called to handle a target for controlled ' +
33
- 'events. This error is likely caused by a bug in React. Please file an issue.',
34
- );
35
- }
36
-
31
const stateNode = internalInstance.stateNode;
32
// Guard against Fiber being unmounted.
33
if (stateNode) {
34
const props = getFiberCurrentPropsFromNode(stateNode);
41
- restoreImpl(internalInstance.stateNode, internalInstance.type, props);
35
+ restoreControlledState(
36
+ internalInstance.stateNode,
37
+ internalInstance.type,
38
+ props,
39
+ );
40
}
41
}
42
45
-export function setRestoreImplementation(
46
- impl: (domElement: Element, tag: string, props: Object) => void,
47
-): void {
48
- restoreImpl = impl;
49
-}
50
-
43
export function enqueueStateRestore(target: Node): void {
44
if (restoreTarget) {
45
if (restoreQueue) {
packages/react-dom-bindings/src/events/ReactDOMEventListener.js
+1
-1
@@ -19,8 +19,8 @@ import {
19
hasQueuedDiscreteEvents,
20
clearIfContinuousEvent,
21
queueIfContinuousEvent,
22
- attemptSynchronousHydration,
22
} from './ReactDOMEventReplaying';
23
+import {attemptSynchronousHydration} from 'react-reconciler/src/ReactFiberReconciler';
24
import {
25
getNearestMountedFiber,
26
getContainerFromFiber,
packages/react-dom-bindings/src/events/ReactDOMEventReplaying.js
+10
-43
@@ -38,49 +38,16 @@ import {HostRoot, SuspenseComponent} from 'react-reconciler/src/ReactWorkTags';
38
import {isHigherEventPriority} from 'react-reconciler/src/ReactEventPriorities';
39
import {isRootDehydrated} from 'react-reconciler/src/ReactFiberShellHydration';
40
41
-let _attemptSynchronousHydration: (fiber: Object) => void;
42
-
43
-export function setAttemptSynchronousHydration(fn: (fiber: Object) => void) {
44
- _attemptSynchronousHydration = fn;
45
-}
46
-
47
-export function attemptSynchronousHydration(fiber: Object) {
48
- _attemptSynchronousHydration(fiber);
49
-}
50
-
51
-let attemptDiscreteHydration: (fiber: Object) => void;
52
-
53
-export function setAttemptDiscreteHydration(fn: (fiber: Object) => void) {
54
- attemptDiscreteHydration = fn;
55
-}
56
-
57
-let attemptContinuousHydration: (fiber: Object) => void;
58
-
59
-export function setAttemptContinuousHydration(fn: (fiber: Object) => void) {
60
- attemptContinuousHydration = fn;
61
-}
62
-
63
-let attemptHydrationAtCurrentPriority: (fiber: Object) => void;
64
-
65
-export function setAttemptHydrationAtCurrentPriority(
66
- fn: (fiber: Object) => void,
67
-) {
68
- attemptHydrationAtCurrentPriority = fn;
69
-}
70
-
71
-let getCurrentUpdatePriority: () => EventPriority;
72
-
73
-export function setGetCurrentUpdatePriority(fn: () => EventPriority) {
74
- getCurrentUpdatePriority = fn;
75
-}
76
-
77
-let attemptHydrationAtPriority: <T>(priority: EventPriority, fn: () => T) => T;
78
-
79
-export function setAttemptHydrationAtPriority(
80
- fn: <T>(priority: EventPriority, fn: () => T) => T,
81
-) {
82
- attemptHydrationAtPriority = fn;
83
-}
41
+import {
42
+ attemptSynchronousHydration,
43
+ attemptDiscreteHydration,
44
+ attemptContinuousHydration,
45
+ attemptHydrationAtCurrentPriority,
46
+} from 'react-reconciler/src/ReactFiberReconciler';
47
+import {
48
+ runWithPriority as attemptHydrationAtPriority,
49
+ getCurrentUpdatePriority,
50
+} from 'react-reconciler/src/ReactEventPriorities';
51
52
// TODO: Upgrade this definition once we're on a newer version of Flow that
53
// has this definition built-in.
packages/react-dom-bindings/src/events/ReactDOMUpdateBatching.js
+6
-19
@@ -10,21 +10,18 @@ import {
10
restoreStateIfNeeded,
11
} from './ReactDOMControlledComponent';
12
13
+import {
14
+ batchedUpdates as batchedUpdatesImpl,
15
+ discreteUpdates as discreteUpdatesImpl,
16
+ flushSync as flushSyncImpl,
17
+} from 'react-reconciler/src/ReactFiberReconciler';
18
+
19
// Used as a way to call batchedUpdates when we don't have a reference to
20
// the renderer. Such as when we're dispatching events or if third party
21
// libraries need to call batchedUpdates. Eventually, this API will go away when
22
// everything is batched by default. We'll then have a similar API to opt-out of
23
// scheduled work and instead do synchronous work.
24
19
-// Defaults
20
-let batchedUpdatesImpl = function (fn, bookkeeping) {
21
- return fn(bookkeeping);
22
-};
23
-let discreteUpdatesImpl = function (fn, a, b, c, d) {
24
- return fn(a, b, c, d);
25
-};
26
-let flushSyncImpl = function () {};
27
-
25
let isInsideEventHandler = false;
26
27
function finishEventHandler() {
@@ -63,13 +60,3 @@ export function batchedUpdates(fn, a, b) {
60
export function discreteUpdates(fn, a, b, c, d) {
61
return discreteUpdatesImpl(fn, a, b, c, d);
62
}
66
-
67
-export function setBatchingImplementation(
68
- _batchedUpdatesImpl,
69
- _discreteUpdatesImpl,
70
- _flushSyncImpl,
71
-) {
72
- batchedUpdatesImpl = _batchedUpdatesImpl;
73
- discreteUpdatesImpl = _discreteUpdatesImpl;
74
- flushSyncImpl = _flushSyncImpl;
75
-}
packages/react-dom/src/client/ReactDOM.js
+1
-34
@@ -34,20 +34,12 @@ import {createEventHandle} from 'react-dom-bindings/src/client/ReactDOMEventHand
34
35
import {
36
batchedUpdates,
37
- discreteUpdates,
37
flushSync as flushSyncWithoutWarningIfAlreadyRendering,
38
isAlreadyRendering,
39
flushControlled,
40
injectIntoDevTools,
42
- attemptSynchronousHydration,
43
- attemptDiscreteHydration,
44
- attemptContinuousHydration,
45
- attemptHydrationAtCurrentPriority,
41
} from 'react-reconciler/src/ReactFiberReconciler';
47
-import {
48
- runWithPriority,
49
- getCurrentUpdatePriority,
50
-} from 'react-reconciler/src/ReactEventPriorities';
42
+import {runWithPriority} from 'react-reconciler/src/ReactEventPriorities';
43
import {createPortal as createPortalImpl} from 'react-reconciler/src/ReactPortal';
44
import {canUseDOM} from 'shared/ExecutionEnvironment';
45
import ReactVersion from 'shared/ReactVersion';
@@ -58,18 +50,7 @@ import {
50
getNodeFromInstance,
51
getFiberCurrentPropsFromNode,
52
} from 'react-dom-bindings/src/client/ReactDOMComponentTree';
61
-import {restoreControlledState} from 'react-dom-bindings/src/client/ReactDOMComponent';
62
-import {
63
- setAttemptSynchronousHydration,
64
- setAttemptDiscreteHydration,
65
- setAttemptContinuousHydration,
66
- setAttemptHydrationAtCurrentPriority,
67
- setGetCurrentUpdatePriority,
68
- setAttemptHydrationAtPriority,
69
-} from 'react-dom-bindings/src/events/ReactDOMEventReplaying';
70
-import {setBatchingImplementation} from 'react-dom-bindings/src/events/ReactDOMUpdateBatching';
53
import {
72
- setRestoreImplementation,
54
enqueueStateRestore,
55
restoreStateIfNeeded,
56
} from 'react-dom-bindings/src/events/ReactDOMControlledComponent';
@@ -82,13 +63,6 @@ export {
63
preinit,
64
} from 'react-dom-bindings/src/shared/ReactDOMFloat';
65
85
-setAttemptSynchronousHydration(attemptSynchronousHydration);
86
-setAttemptDiscreteHydration(attemptDiscreteHydration);
87
-setAttemptContinuousHydration(attemptContinuousHydration);
88
-setAttemptHydrationAtCurrentPriority(attemptHydrationAtCurrentPriority);
89
-setGetCurrentUpdatePriority(getCurrentUpdatePriority);
90
-setAttemptHydrationAtPriority(runWithPriority);
91
-
66
if (__DEV__) {
67
if (
68
typeof Map !== 'function' ||
@@ -108,13 +82,6 @@ if (__DEV__) {
82
}
83
}
84
111
-setRestoreImplementation(restoreControlledState);
112
-setBatchingImplementation(
113
- batchedUpdates,
114
- discreteUpdates,
115
- flushSyncWithoutWarningIfAlreadyRendering,
116
-);
117
-
85
function createPortal(
86
children: ReactNodeList,
87
container: Element | DocumentFragment,