Remove Array.from() from hot path (#19908)
* Remove Array.from() from hot path * Fix build Don't declare block variables inside loops
Dan Abramov committed
Sep 25, 2020 at 11:33 UTC
0a008044945a9dcdc9543575a8ba90b1aaacf56c
2 files changed
+54
-83
packages/react-dom/src/events/DOMPluginEventSystem.js
+51
-79
@@ -726,8 +726,9 @@ export function accumulateSinglePhaseListeners(
726
inCapturePhase: boolean,
727
accumulateTargetOnly: boolean,
728
): void {
729
- const bubbled = event._reactName;
730
- const captured = bubbled !== null ? bubbled + 'Capture' : null;
729
+ const bubbleName = event._reactName;
730
+ const captureName = bubbleName !== null ? bubbleName + 'Capture' : null;
731
+ const reactEventName = inCapturePhase ? captureName : bubbleName;
732
const listeners: Array<DispatchListener> = [];
733
734
let instance = targetFiber;
@@ -739,48 +740,34 @@ export function accumulateSinglePhaseListeners(
740
const {stateNode, tag} = instance;
741
// Handle listeners that are on HostComponents (i.e. <div>)
742
if (tag === HostComponent && stateNode !== null) {
742
- const currentTarget = stateNode;
743
- lastHostComponent = currentTarget;
744
- // For Event Handle listeners
745
- if (enableCreateEventHandleAPI) {
746
- const eventHandlerlisteners = getEventHandlerListeners(currentTarget);
743
+ lastHostComponent = stateNode;
744
748
- if (eventHandlerlisteners !== null) {
749
- const eventHandlerlistenersArr = Array.from(eventHandlerlisteners);
750
- for (let i = 0; i < eventHandlerlistenersArr.length; i++) {
751
- const {
752
- callback,
753
- capture: isCapturePhaseListener,
754
- type,
755
- } = eventHandlerlistenersArr[i];
756
- if (type === targetType) {
757
- if (isCapturePhaseListener && inCapturePhase) {
758
- listeners.push(
759
- createDispatchListener(instance, callback, currentTarget),
760
- );
761
- } else if (!isCapturePhaseListener && !inCapturePhase) {
762
- listeners.push(
763
- createDispatchListener(instance, callback, currentTarget),
764
- );
765
- }
745
+ // createEventHandle listeners
746
+ if (enableCreateEventHandleAPI) {
747
+ const eventHandlerListeners = getEventHandlerListeners(
748
+ lastHostComponent,
749
+ );
750
+ if (eventHandlerListeners !== null) {
751
+ eventHandlerListeners.forEach(entry => {
752
+ if (entry.type === targetType && entry.capture === inCapturePhase) {
753
+ listeners.push(
754
+ createDispatchListener(
755
+ instance,
756
+ entry.callback,
757
+ (lastHostComponent: any),
758
+ ),
759
+ );
760
}
767
- }
768
- }
769
- }
770
- // Standard React on* listeners, i.e. onClick prop
771
- if (captured !== null && inCapturePhase) {
772
- const captureListener = getListener(instance, captured);
773
- if (captureListener != null) {
774
- listeners.push(
775
- createDispatchListener(instance, captureListener, currentTarget),
776
- );
761
+ });
762
}
763
}
779
- if (bubbled !== null && !inCapturePhase) {
780
- const bubbleListener = getListener(instance, bubbled);
781
- if (bubbleListener != null) {
764
+
765
+ // Standard React on* listeners, i.e. onClick or onClickCapture
766
+ if (reactEventName !== null) {
767
+ const listener = getListener(instance, reactEventName);
768
+ if (listener != null) {
769
listeners.push(
783
- createDispatchListener(instance, bubbleListener, currentTarget),
770
+ createDispatchListener(instance, listener, lastHostComponent),
771
);
772
}
773
}
@@ -791,32 +778,23 @@ export function accumulateSinglePhaseListeners(
778
lastHostComponent !== null &&
779
stateNode !== null
780
) {
781
+ // Scopes
782
const reactScopeInstance = stateNode;
795
- const eventHandlerlisteners = getEventHandlerListeners(
783
+ const eventHandlerListeners = getEventHandlerListeners(
784
reactScopeInstance,
785
);
798
- const lastCurrentTarget = ((lastHostComponent: any): Element);
799
-
800
- if (eventHandlerlisteners !== null) {
801
- const eventHandlerlistenersArr = Array.from(eventHandlerlisteners);
802
- for (let i = 0; i < eventHandlerlistenersArr.length; i++) {
803
- const {
804
- callback,
805
- capture: isCapturePhaseListener,
806
- type,
807
- } = eventHandlerlistenersArr[i];
808
- if (type === targetType) {
809
- if (isCapturePhaseListener && inCapturePhase) {
810
- listeners.push(
811
- createDispatchListener(instance, callback, lastCurrentTarget),
812
- );
813
- } else if (!isCapturePhaseListener && !inCapturePhase) {
814
- listeners.push(
815
- createDispatchListener(instance, callback, lastCurrentTarget),
816
- );
817
- }
786
+ if (eventHandlerListeners !== null) {
787
+ eventHandlerListeners.forEach(entry => {
788
+ if (entry.type === targetType && entry.capture === inCapturePhase) {
789
+ listeners.push(
790
+ createDispatchListener(
791
+ instance,
792
+ entry.callback,
793
+ (lastHostComponent: any),
794
+ ),
795
+ );
796
}
819
- }
797
+ });
798
}
799
}
800
// If we are only accumulating events for the target, then we don't
@@ -844,8 +822,8 @@ export function accumulateTwoPhaseListeners(
822
dispatchQueue: DispatchQueue,
823
event: ReactSyntheticEvent,
824
): void {
847
- const bubbled = event._reactName;
848
- const captured = bubbled !== null ? bubbled + 'Capture' : null;
825
+ const bubbleName = event._reactName;
826
+ const captureName = bubbleName !== null ? bubbleName + 'Capture' : null;
827
const listeners: Array<DispatchListener> = [];
828
let instance = targetFiber;
829
@@ -856,16 +834,16 @@ export function accumulateTwoPhaseListeners(
834
if (tag === HostComponent && stateNode !== null) {
835
const currentTarget = stateNode;
836
// Standard React on* listeners, i.e. onClick prop
859
- if (captured !== null) {
860
- const captureListener = getListener(instance, captured);
837
+ if (captureName !== null) {
838
+ const captureListener = getListener(instance, captureName);
839
if (captureListener != null) {
840
listeners.unshift(
841
createDispatchListener(instance, captureListener, currentTarget),
842
);
843
}
844
}
867
- if (bubbled !== null) {
868
- const bubbleListener = getListener(instance, bubbled);
845
+ if (bubbleName !== null) {
846
+ const bubbleListener = getListener(instance, bubbleName);
847
if (bubbleListener != null) {
848
listeners.push(
849
createDispatchListener(instance, bubbleListener, currentTarget),
@@ -1026,20 +1004,14 @@ export function accumulateEventHandleNonManagedNodeListeners(
1004
1005
const eventListeners = getEventHandlerListeners(currentTarget);
1006
if (eventListeners !== null) {
1029
- const listenersArr = Array.from(eventListeners);
1007
const targetType = ((event.type: any): DOMEventName);
1031
-
1032
- for (let i = 0; i < listenersArr.length; i++) {
1033
- const listener = listenersArr[i];
1034
- const {callback, capture: isCapturePhaseListener, type} = listener;
1035
- if (type === targetType) {
1036
- if (inCapturePhase && isCapturePhaseListener) {
1037
- listeners.push(createDispatchListener(null, callback, currentTarget));
1038
- } else if (!inCapturePhase && !isCapturePhaseListener) {
1039
- listeners.push(createDispatchListener(null, callback, currentTarget));
1040
- }
1008
+ eventListeners.forEach(entry => {
1009
+ if (entry.type === targetType && entry.capture === inCapturePhase) {
1010
+ listeners.push(
1011
+ createDispatchListener(null, entry.callback, currentTarget),
1012
+ );
1013
}
1042
- }
1014
+ });
1015
}
1016
if (listeners.length !== 0) {
1017
dispatchQueue.push(createDispatchEntry(event, listeners));
packages/react-interactions/events/src/dom/create-event-handle/useEvent.js
+3
-4
@@ -50,10 +50,9 @@ export default function useEvent(
50
clears.set(target, clear);
51
},
52
clear(): void {
53
- const clearsArr = Array.from(clears.values());
54
- for (let i = 0; i < clearsArr.length; i++) {
55
- clearsArr[i]();
56
- }
53
+ clears.forEach(c => {
54
+ c();
55
+ });
56
clears.clear();
57
},
58
};