-
Notifications
You must be signed in to change notification settings - Fork 47.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix a regression that caused us to listen to extra events at the top #12878
Conversation
I find it a bit easier to follow than many comparison conditions.
They are being assigned below anyway. This is likely a copypasta from the FOCUS/BLUR special case (which *does* need those assignments).
Their logic is identical.
ReactDOM: size: 0.0%, gzip: -0.0% Details of bundled changes.Comparing: ad27845...53d0d36 react-dom
Generated by 🚫 dangerJS |
Hmm. I started looking into special cases and it looks like |
The case I added was wrong (just like including this event in the top level list was always wrong). In fact it never bubbles, even for <img>. And since we don't special case it in the <img> event attachment logic when we create it, we never supported <img onLoadStart> at all. We could fix it. But Chrome doesn't support it either: https://bugs.chromium.org/p/chromium/issues/detail?id=458851. Nobody asked us for it yet. And supporting it would require attaching an extra listener to every <img>. So maybe we don't need it? Let's document the existing state of things.
formRef.current.dispatchEvent( | ||
new Event('submit', { | ||
// https://developer.mozilla.org/en-US/docs/Web/Events/submit | ||
bubbles: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be nice to have a bubbles-false test for this too if we don't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When would it be false?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Old browsers I think. That's why we listen on the element at all.
bubbles: true, | ||
}), | ||
); | ||
expect(handleSubmit).toHaveBeenCalledTimes(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This failed before, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it failed before your fix
// Some of them bubble so we don't want them to fire twice. | ||
break; | ||
default: | ||
// By default, listen on the top level to all non-media events. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add:
// Media events don't bubble so adding the listener wouldn't do anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
break; | ||
default: | ||
// By default, listen on the top level to all non-media events. | ||
const isNonMediaEvent = mediaEventTypes.indexOf(dependency) === -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO this would be easier to read as
isMediaEvent
!== -1
if (!isMediaEvent)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Force-pushed the version without the commit that changed this
I think this should fix the regression introduced in #12629 and that @sophiebits has patched over in #12877.
The first three commits are small refactors (I can remove them but I found the final form easier to read with these changes). The last one fixes the logic.
I'll need to work on some way to test this and verify it’s correct. Here’s the methodology with which I arrived at this solution:
Take a list of all DOM event types in master
For each type, record whether it exists in either of two mappings that were deleted in #12629:
topLevelTypes
ormediaEventTypes
. Some types were new in master (pointer events) which I treat as if they were intopLevelTypes
.After doing this categorization, I ended up with four lists:
NOT top AND NOT media
TOP_INVALID
TOP_RESET
TOP_SUBMIT
NOT top AND media
TOP_ABORT
TOP_CAN_PLAY
TOP_CAN_PLAY_THROUGH
TOP_DURATION_CHANGE
TOP_EMPTIED
TOP_ENCRYPTED
TOP_ENDED
TOP_ERROR
TOP_LOADED_DATA
TOP_LOADED_METADATA
TOP_PAUSE
TOP_PLAY
TOP_PLAYING
TOP_PROGRESS
TOP_RATE_CHANGE
TOP_SEEKED
TOP_SEEKING
TOP_STALLED
TOP_SUSPEND
TOP_TIME_UPDATE
TOP_VOLUME_CHANGE
TOP_WAITING
top AND media
TOP_LOAD_START
top AND NOT media
TOP_ANIMATION_END
TOP_ANIMATION_ITERATION
TOP_ANIMATION_START
TOP_BLUR
TOP_CANCEL
TOP_CHANGE
TOP_CLICK
TOP_CLOSE
TOP_COMPOSITION_END
TOP_COMPOSITION_START
TOP_COMPOSITION_UPDATE
TOP_CONTEXT_MENU
TOP_COPY
TOP_CUT
TOP_DOUBLE_CLICK
TOP_DRAG
TOP_DRAG_END
TOP_DRAG_ENTER
TOP_DRAG_EXIT
TOP_DRAG_LEAVE
TOP_DRAG_OVER
TOP_DRAG_START
TOP_DROP
TOP_FOCUS
TOP_GOT_POINTER_CAPTURE
TOP_INPUT
TOP_KEY_DOWN
TOP_KEY_PRESS
TOP_KEY_UP
TOP_LOAD
TOP_LOST_POINTER_CAPTURE
TOP_MOUSE_DOWN
TOP_MOUSE_MOVE
TOP_MOUSE_OUT
TOP_MOUSE_OVER
TOP_MOUSE_UP
TOP_PASTE
TOP_POINTER_CANCEL
TOP_POINTER_DOWN
TOP_POINTER_ENTER
TOP_POINTER_LEAVE
TOP_POINTER_MOVE
TOP_POINTER_OUT
TOP_POINTER_OVER
TOP_POINTER_UP
TOP_SCROLL
TOP_SELECTION_CHANGE
TOP_TEXT_INPUT
TOP_TOGGLE
TOP_TOUCH_CANCEL
TOP_TOUCH_END
TOP_TOUCH_MOVE
TOP_TOUCH_START
TOP_TRANSITION_END
TOP_WHEEL
From these lists, it follows that:
TOP_LOAD_START
is an exception to the previous rule: even though it’s a media event, we listen to it on the top level.TOP_INVALID
,TOP_RESET
, andTOP_SUBMIT
) that are neither in the media nor the top whitelist. So we should exclude them too.That’s reflected in my switch structure:
Note that I’m introducing an
indexOf
lookup there. I think it’s fine because this code only runs once per event, andindexOf
is very fast on small arrays (mediaEventTypes
has 23 elements). So I wouldn’t expect this to regress anything. But I can turn it into an object lookup if needed.