Skip to content
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

ReactDOM.useEvent: Add support for experimental scopes API #18375

Merged
merged 2 commits into from
Mar 26, 2020

Conversation

trueadm
Copy link
Contributor

@trueadm trueadm commented Mar 24, 2020

This is the last big piece of the useEvent API puzzle. It ports the existing behavior in React Flare, where you can attach listeners to the experimental Scopes API. This means that with useEvent you can attach events to a "scope" rather than a physical EventTarget, making way for us to be able to port the internal a11y components and their usages of this over to useEvent, allowing us to remove React Flare. This feature is a very important one, as it allows us to attach events to something that doesn't require a physical DOM element, as these can be problematic in places with <table> and <select>, plus adding in additional DOM wrapper elements can break the semantics of accessibility tools and CSS styling – which is why we offered this feature for Scopes with Flare.

@facebook-github-bot facebook-github-bot added CLA Signed React Core Team Opened by a member of the React Core Team labels Mar 24, 2020
@codesandbox-ci
Copy link

codesandbox-ci bot commented Mar 24, 2020

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 00cfbaa:

Sandbox Source
confident-lehmann-15t9p Configuration

@sizebot
Copy link

sizebot commented Mar 24, 2020

Warnings
⚠️ Base commit is broken: 0140118

Size changes (stable)

Generated by 🚫 dangerJS against 2d1b222

@sizebot
Copy link

sizebot commented Mar 24, 2020

Warnings
⚠️ Base commit is broken: 0140118

Size changes (experimental)

Generated by 🚫 dangerJS against 2d1b222

Copy link
Contributor

@threepointone threepointone left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks fine to me, and I assume this work has already been validated by the flare effort.

const type = ((event.type: any): DOMTopLevelEventType);
const listeners = eventTypeMap.get(type);
if (listeners !== undefined) {
const captureListeners = Array.from(listeners.captured);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw I noticed we use this in a few places right now, so we should probably add Array.from to this page https://reactjs.org/docs/javascript-environment-requirements.html

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, although we don't need to add it till v17.

@trueadm trueadm merged commit a16b349 into facebook:master Mar 26, 2020
@trueadm trueadm deleted the use-event-scopes branch March 26, 2020 13:29
acdlite added a commit to acdlite/react that referenced this pull request Mar 31, 2020
…acebook#18375)"

This reverts commit a16b349.

* ReactDOM.useEvent: Add support for experimental scopes API
acdlite added a commit to acdlite/react that referenced this pull request Mar 31, 2020
…acebook#18375)"

This reverts commit a16b349.

* ReactDOM.useEvent: Add support for experimental scopes API
@acdlite acdlite mentioned this pull request Mar 31, 2020
acdlite added a commit that referenced this pull request Mar 31, 2020
* Revert "ReactDOM.useEvent: enable on internal www and add inspection test (#18395)"

This reverts commit e0ab1a4.

* Revert "ReactDOM.useEvent: Add support for experimental scopes API (#18375)"

This reverts commit a16b349.

* ReactDOM.useEvent: Add support for experimental scopes API
const listener = bubbleListeners[i];
const {callback} = listener;
dispatchListeners.push(callback);
dispatchInstances.push(((lastHostComponent: any): Element));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell, this is what caused the production crashes with today’s sync. This is only set if we “met” a host component in the above traversal before we “met” a Scope. Does anything actually guarantee that? We should probably be more careful with any casts in the production codepaths.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind, see below. I got confused between two code paths. I’m still not sure this was safe though — could the innermost instance be a TextInstance for example, followed by a Scope? I think that could still crash.

Copy link
Contributor Author

@trueadm trueadm Mar 31, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The target can only ever be a DOM element as you can't have listeners on text nodes, I'll add a null check for this in the follow up PR too though!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can't have listeners, but could it be bubbling from a text node?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Text nodes can't have children, so there should be no case where we'd ever propagate through into or from a text node.

Copy link
Collaborator

@gaearon gaearon Mar 31, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I mean something like this:

<div>
  <Scope>
    {'hello'}{'world'}
  </Scope>
</div>

If I dispatch an event on the text node, won't it trigger this case?

Copy link
Contributor Author

@trueadm trueadm Mar 31, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are you dispatching the event? Whilst you can manually create an bubbling event and dispatch it directly on a text node (using the Node.prototype.dispatchEvent), this won't ever occur from an actual real-world event that the user would do.

We only store the host component when it's an actual host component instance (by checking the tag). I can make it so we do for those too though. :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this won't ever occur from an actual real-world event that the user would do.

I wouldn't be so sure, I remember text nodes firing events in Firefox in some cases. Not saying it should be common but may happen in production.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added support for HostText + test in #18441.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed React Core Team Opened by a member of the React Core Team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants