Skip to content

Commit c55d56f

Browse files
committed
React Event System: cleanup plugins + break out update batching logic
Include changes
1 parent fe2cb52 commit c55d56f

11 files changed

+225
-114
lines changed

packages/legacy-events/EventPluginRegistry.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,3 +241,20 @@ export function injectEventPluginsByName(
241241
recomputePluginOrdering();
242242
}
243243
}
244+
245+
export function injectEventPlugins(
246+
eventPlugins: [PluginModule<AnyNativeEvent>],
247+
): void {
248+
for (let i = 0; i < eventPlugins.length; i++) {
249+
const pluginModule = eventPlugins[i];
250+
plugins.push(pluginModule);
251+
const publishedEvents = pluginModule.eventTypes;
252+
for (const eventName in publishedEvents) {
253+
publishEventForPlugin(
254+
publishedEvents[eventName],
255+
pluginModule,
256+
eventName,
257+
);
258+
}
259+
}
260+
}

packages/legacy-events/ReactGenericBatching.js

Lines changed: 1 addition & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,6 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
import {
9-
needsStateRestore,
10-
restoreStateIfNeeded,
11-
} from './ReactControlledComponent';
12-
13-
import {enableDeprecatedFlareAPI} from 'shared/ReactFeatureFlags';
14-
import {invokeGuardedCallbackAndCatchFirstError} from 'shared/ReactErrorUtils';
15-
168
// Used as a way to call batchedUpdates when we don't have a reference to
179
// the renderer. Such as when we're dispatching events or if third party
1810
// libraries need to call batchedUpdates. Eventually, this API will go away when
@@ -32,21 +24,6 @@ let batchedEventUpdatesImpl = batchedUpdatesImpl;
3224
let isInsideEventHandler = false;
3325
let isBatchingEventUpdates = false;
3426

35-
function finishEventHandler() {
36-
// Here we wait until all updates have propagated, which is important
37-
// when using controlled components within layers:
38-
// https://github.com/facebook/react/issues/1698
39-
// Then we restore state of any controlled component.
40-
const controlledComponentsHavePendingUpdates = needsStateRestore();
41-
if (controlledComponentsHavePendingUpdates) {
42-
// If a controlled event was fired, we may need to restore the state of
43-
// the DOM node back to the controlled value. This is necessary when React
44-
// bails out of the update without touching the DOM.
45-
flushDiscreteUpdatesImpl();
46-
restoreStateIfNeeded();
47-
}
48-
}
49-
5027
export function batchedUpdates(fn, bookkeeping) {
5128
if (isInsideEventHandler) {
5229
// If we are currently inside another batch, we need to wait until it
@@ -58,7 +35,6 @@ export function batchedUpdates(fn, bookkeeping) {
5835
return batchedUpdatesImpl(fn, bookkeeping);
5936
} finally {
6037
isInsideEventHandler = false;
61-
finishEventHandler();
6238
}
6339
}
6440

@@ -73,19 +49,6 @@ export function batchedEventUpdates(fn, a, b) {
7349
return batchedEventUpdatesImpl(fn, a, b);
7450
} finally {
7551
isBatchingEventUpdates = false;
76-
finishEventHandler();
77-
}
78-
}
79-
80-
// This is for the React Flare event system
81-
export function executeUserEventHandler(fn: any => void, value: any): void {
82-
const previouslyInEventHandler = isInsideEventHandler;
83-
try {
84-
isInsideEventHandler = true;
85-
const type = typeof value === 'object' && value !== null ? value.type : '';
86-
invokeGuardedCallbackAndCatchFirstError(type, fn, undefined, value);
87-
} finally {
88-
isInsideEventHandler = previouslyInEventHandler;
8952
}
9053
}
9154

@@ -97,32 +60,12 @@ export function discreteUpdates(fn, a, b, c, d) {
9760
} finally {
9861
isInsideEventHandler = prevIsInsideEventHandler;
9962
if (!isInsideEventHandler) {
100-
finishEventHandler();
10163
}
10264
}
10365
}
10466

105-
let lastFlushedEventTimeStamp = 0;
10667
export function flushDiscreteUpdatesIfNeeded(timeStamp: number) {
107-
// event.timeStamp isn't overly reliable due to inconsistencies in
108-
// how different browsers have historically provided the time stamp.
109-
// Some browsers provide high-resolution time stamps for all events,
110-
// some provide low-resolution time stamps for all events. FF < 52
111-
// even mixes both time stamps together. Some browsers even report
112-
// negative time stamps or time stamps that are 0 (iOS9) in some cases.
113-
// Given we are only comparing two time stamps with equality (!==),
114-
// we are safe from the resolution differences. If the time stamp is 0
115-
// we bail-out of preventing the flush, which can affect semantics,
116-
// such as if an earlier flush removes or adds event listeners that
117-
// are fired in the subsequent flush. However, this is the same
118-
// behaviour as we had before this change, so the risks are low.
119-
if (
120-
!isInsideEventHandler &&
121-
(!enableDeprecatedFlareAPI ||
122-
timeStamp === 0 ||
123-
lastFlushedEventTimeStamp !== timeStamp)
124-
) {
125-
lastFlushedEventTimeStamp = timeStamp;
68+
if (!isInsideEventHandler) {
12669
flushDiscreteUpdatesImpl();
12770
}
12871
}

packages/react-dom/src/client/ReactDOM.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,6 @@ import {
3939
} from 'react-reconciler/src/ReactFiberReconciler';
4040
import {createPortal as createPortalImpl} from 'react-reconciler/src/ReactPortal';
4141
import {canUseDOM} from 'shared/ExecutionEnvironment';
42-
import {setBatchingImplementation} from 'legacy-events/ReactGenericBatching';
43-
import {
44-
setRestoreImplementation,
45-
enqueueStateRestore,
46-
restoreStateIfNeeded,
47-
} from 'legacy-events/ReactControlledComponent';
4842
import {runEventsInBatch} from 'legacy-events/EventBatching';
4943
import {
5044
eventNameDispatchConfigs,
@@ -69,6 +63,12 @@ import {
6963
setAttemptHydrationAtCurrentPriority,
7064
queueExplicitHydrationTarget,
7165
} from '../events/ReactDOMEventReplaying';
66+
import {setBatchingImplementation} from '../events/ReactDOMUpdateBatching';
67+
import {
68+
setRestoreImplementation,
69+
enqueueStateRestore,
70+
restoreStateIfNeeded,
71+
} from '../events/ReactDOMControlledComponent';
7272

7373
setAttemptSynchronousHydration(attemptSynchronousHydration);
7474
setAttemptUserBlockingHydration(attemptUserBlockingHydration);

packages/react-dom/src/client/ReactDOMClientInjection.js

Lines changed: 48 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,43 +20,55 @@ import SimpleEventPlugin from '../events/SimpleEventPlugin';
2020
import {
2121
injectEventPluginOrder,
2222
injectEventPluginsByName,
23+
injectEventPlugins,
2324
} from 'legacy-events/EventPluginRegistry';
25+
import {enableModernEventSystem} from 'shared/ReactFeatureFlags';
2426

25-
/**
26-
* Specifies a deterministic ordering of `EventPlugin`s. A convenient way to
27-
* reason about plugins, without having to package every one of them. This
28-
* is better than having plugins be ordered in the same order that they
29-
* are injected because that ordering would be influenced by the packaging order.
30-
* `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that
31-
* preventing default on events is convenient in `SimpleEventPlugin` handlers.
32-
*/
33-
const DOMEventPluginOrder = [
34-
'ResponderEventPlugin',
35-
'SimpleEventPlugin',
36-
'EnterLeaveEventPlugin',
37-
'ChangeEventPlugin',
38-
'SelectEventPlugin',
39-
'BeforeInputEventPlugin',
40-
];
27+
if (enableModernEventSystem) {
28+
/**
29+
* Specifies a deterministic ordering of `EventPlugin`s. A convenient way to
30+
* reason about plugins, without having to package every one of them. This
31+
* is better than having plugins be ordered in the same order that they
32+
* are injected because that ordering would be influenced by the packaging order.
33+
* `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that
34+
* preventing default on events is convenient in `SimpleEventPlugin` handlers.
35+
*/
36+
const DOMEventPluginOrder = [
37+
'ResponderEventPlugin',
38+
'SimpleEventPlugin',
39+
'EnterLeaveEventPlugin',
40+
'ChangeEventPlugin',
41+
'SelectEventPlugin',
42+
'BeforeInputEventPlugin',
43+
];
4144

42-
/**
43-
* Inject modules for resolving DOM hierarchy and plugin ordering.
44-
*/
45-
injectEventPluginOrder(DOMEventPluginOrder);
46-
setComponentTree(
47-
getFiberCurrentPropsFromNode,
48-
getInstanceFromNode,
49-
getNodeFromInstance,
50-
);
45+
/**
46+
* Inject modules for resolving DOM hierarchy and plugin ordering.
47+
*/
48+
injectEventPluginOrder(DOMEventPluginOrder);
49+
setComponentTree(
50+
getFiberCurrentPropsFromNode,
51+
getInstanceFromNode,
52+
getNodeFromInstance,
53+
);
5154

52-
/**
53-
* Some important event plugins included by default (without having to require
54-
* them).
55-
*/
56-
injectEventPluginsByName({
57-
SimpleEventPlugin: SimpleEventPlugin,
58-
EnterLeaveEventPlugin: EnterLeaveEventPlugin,
59-
ChangeEventPlugin: ChangeEventPlugin,
60-
SelectEventPlugin: SelectEventPlugin,
61-
BeforeInputEventPlugin: BeforeInputEventPlugin,
62-
});
55+
/**
56+
* Some important event plugins included by default (without having to require
57+
* them).
58+
*/
59+
injectEventPluginsByName({
60+
SimpleEventPlugin: SimpleEventPlugin,
61+
EnterLeaveEventPlugin: EnterLeaveEventPlugin,
62+
ChangeEventPlugin: ChangeEventPlugin,
63+
SelectEventPlugin: SelectEventPlugin,
64+
BeforeInputEventPlugin: BeforeInputEventPlugin,
65+
});
66+
} else {
67+
injectEventPlugins([
68+
SimpleEventPlugin,
69+
EnterLeaveEventPlugin,
70+
ChangeEventPlugin,
71+
SelectEventPlugin,
72+
BeforeInputEventPlugin,
73+
]);
74+
}

packages/react-dom/src/events/ChangeEventPlugin.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
*/
77

88
import {runEventsInBatch} from 'legacy-events/EventBatching';
9-
import {enqueueStateRestore} from 'legacy-events/ReactControlledComponent';
10-
import {batchedUpdates} from 'legacy-events/ReactGenericBatching';
119
import SyntheticEvent from 'legacy-events/SyntheticEvent';
1210
import isTextInputElement from './isTextInputElement';
1311
import {canUseDOM} from 'shared/ExecutionEnvironment';
@@ -27,9 +25,11 @@ import isEventSupported from './isEventSupported';
2725
import {getNodeFromInstance} from '../client/ReactDOMComponentTree';
2826
import {updateValueIfChanged} from '../client/inputValueTracking';
2927
import {setDefaultValue} from '../client/ReactDOMInput';
28+
import {enqueueStateRestore} from './ReactDOMControlledComponent';
3029

3130
import {disableInputAttributeSyncing} from 'shared/ReactFeatureFlags';
3231
import accumulateTwoPhaseListeners from './accumulateTwoPhaseListeners';
32+
import {batchedUpdates} from './ReactDOMUpdateBatching';
3333

3434
const eventTypes = {
3535
change: {

packages/react-dom/src/events/DOMLegacyEventPluginSystem.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import {
2222
HostText,
2323
} from 'react-reconciler/src/ReactWorkTags';
2424
import {IS_FIRST_ANCESTOR, PLUGIN_EVENT_SYSTEM} from './EventSystemFlags';
25-
import {batchedEventUpdates} from 'legacy-events/ReactGenericBatching';
2625
import {runEventsInBatch} from 'legacy-events/EventBatching';
2726
import {plugins} from 'legacy-events/EventPluginRegistry';
2827
import accumulateInto from 'legacy-events/accumulateInto';
@@ -45,6 +44,7 @@ import {
4544
mediaEventTypes,
4645
} from './DOMTopLevelEventTypes';
4746
import {addTrappedEventListener} from './ReactDOMEventListener';
47+
import {batchedEventUpdates} from './ReactDOMUpdateBatching';
4848

4949
/**
5050
* Summary of `DOMEventPluginSystem` event handling:

packages/react-dom/src/events/DOMModernPluginEventSystem.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import type {
2424
import type {ReactDOMListener} from '../shared/ReactDOMTypes';
2525

2626
import {registrationNameDependencies} from 'legacy-events/EventPluginRegistry';
27-
import {batchedEventUpdates} from 'legacy-events/ReactGenericBatching';
2827
import {plugins} from 'legacy-events/EventPluginRegistry';
2928
import {
3029
PLUGIN_EVENT_SYSTEM,
@@ -86,6 +85,7 @@ import {
8685
} from '../client/ReactDOMComponentTree';
8786
import {COMMENT_NODE} from '../shared/HTMLNodeType';
8887
import {topLevelEventsToDispatchConfig} from './DOMEventProperties';
88+
import {batchedEventUpdates} from './ReactDOMUpdateBatching';
8989

9090
import {
9191
enableLegacyFBSupport,

packages/react-dom/src/events/DeprecatedDOMEventResponderSystem.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ import {
3030
discreteUpdates,
3131
flushDiscreteUpdatesIfNeeded,
3232
executeUserEventHandler,
33-
} from 'legacy-events/ReactGenericBatching';
34-
import {enqueueStateRestore} from 'legacy-events/ReactControlledComponent';
33+
} from './ReactDOMUpdateBatching';
3534
import type {Fiber} from 'react-reconciler/src/ReactFiber';
3635
import {enableDeprecatedFlareAPI} from 'shared/ReactFeatureFlags';
3736
import invariant from 'shared/invariant';
3837

3938
import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
39+
import {enqueueStateRestore} from './ReactDOMControlledComponent';
4040
import {
4141
ContinuousEvent,
4242
UserBlockingEvent,

packages/legacy-events/ReactControlledComponent.js renamed to packages/react-dom/src/events/ReactDOMControlledComponent.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,18 @@
88
*/
99

1010
import invariant from 'shared/invariant';
11-
1211
import {
1312
getInstanceFromNode,
1413
getFiberCurrentPropsFromNode,
15-
} from './EventPluginUtils';
14+
} from '../client/ReactDOMComponentTree';
1615

1716
// Use to restore controlled state after a change event has fired.
1817

1918
let restoreImpl = null;
2019
let restoreTarget = null;
2120
let restoreQueue = null;
2221

23-
function restoreStateOfTarget(target) {
22+
function restoreStateOfTarget(target: Node) {
2423
// We perform this translation at the end of the event loop so that we
2524
// always receive the correct fiber here
2625
const internalInstance = getInstanceFromNode(target);
@@ -47,7 +46,7 @@ export function setRestoreImplementation(
4746
restoreImpl = impl;
4847
}
4948

50-
export function enqueueStateRestore(target: EventTarget): void {
49+
export function enqueueStateRestore(target: Node): void {
5150
if (restoreTarget) {
5251
if (restoreQueue) {
5352
restoreQueue.push(target);

packages/react-dom/src/events/ReactDOMEventListener.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
1717
// CommonJS interop named imports.
1818
import * as Scheduler from 'scheduler';
1919

20-
import {
21-
discreteUpdates,
22-
flushDiscreteUpdatesIfNeeded,
23-
} from 'legacy-events/ReactGenericBatching';
2420
import {DEPRECATED_dispatchEventForResponderEventSystem} from './DeprecatedDOMEventResponderSystem';
2521
import {
2622
isReplayableDiscreteEvent,
@@ -70,6 +66,10 @@ import {
7066
import {getEventPriorityForPluginSystem} from './DOMEventProperties';
7167
import {dispatchEventForLegacyPluginEventSystem} from './DOMLegacyEventPluginSystem';
7268
import {dispatchEventForPluginEventSystem} from './DOMModernPluginEventSystem';
69+
import {
70+
flushDiscreteUpdatesIfNeeded,
71+
discreteUpdates,
72+
} from './ReactDOMUpdateBatching';
7373

7474
const {
7575
unstable_UserBlockingPriority: UserBlockingPriority,

0 commit comments

Comments
 (0)