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

Don’t add onclick listener to React root #13778

Merged
merged 6 commits into from
Oct 9, 2018

Conversation

philipp-spiess
Copy link
Contributor

Fixes #13777

As part of #11927 we introduced a regression by adding onclick handler to the React root. This causes the whole React tree to flash when tapped on iOS devices (for reasons I outlined in #12989 (comment)).

To fix this, we should only apply onclick listeners to portal roots. I verified that my proposed fix indeed works by checking out our DOM fixtures and adding regression tests.

Strangely, I had to make changes to the DOM fixtures to see the behavior in the first place. This seems to be caused by our normal sites (and
thus their React root) being bigger than the viewport:

An alternative approach to finding out if we're appending to a React root would be to add a third parameter to appendChildToContainer based on the tag of the parent fiber.

Fixes facebook#13777

As part of facebook#11927 we introduced a regression by adding onclick handler
to the React root. This causes the whole React tree to flash
when tapped on iOS devices (for reasons I outlined in facebook#12989 (comment)).

To fix this, we should only apply onclick listeners to portal roots. I
verified that this fix indeed worked by checkout out our DOM fixtures
and added regression tests as well.

Strangely, I had to make changes to the DOM fixtures to see the behavior
in the first place. This seems to be caused by our normal sites being
bigger than the viewport:

![](http://cl.ly/3f18f8b85e91/Screen%20Recording%202018-10-05%20at%2001.32%20AM.gif)

An alternative fix would be to add a third parameter to
`appendChildToContainer` based on the tag of the parent fiber. Although
I think relying on the `_reactRootContainer` property that we set on the
element is less intrusive.
Copy link
Collaborator

@gaearon gaearon left a comment

Choose a reason for hiding this comment

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

I think this is reasonable

@gaearon
Copy link
Collaborator

gaearon commented Oct 4, 2018

This seems to be caused by our normal sites (and thus their React root) being bigger than the viewport:

So the issue only appears when React root is bigger? Or when it is smaller?

I didn't see this in testing. But I don't remember what I used for testing.

@sizebot
Copy link

sizebot commented Oct 4, 2018

Details of bundled changes.

Comparing: d836010...ea25fe7

scheduler

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
scheduler.development.js n/a n/a 0 B 19.17 KB 0 B 5.74 KB UMD_DEV
scheduler.production.min.js n/a n/a 0 B 3.16 KB 0 B 1.53 KB UMD_PROD

Generated by 🚫 dangerJS

@philipp-spiess
Copy link
Contributor Author

philipp-spiess commented Oct 4, 2018

So the issue only appears when React root is bigger? Or when it is smaller?

Only when the React root is smaller than the viewport. In the gif you see the red flashing as long as the text does not cause the viewport to overflow.

This (kinda) explains my strange observations here as well: #12717 (comment)

@@ -341,8 +341,16 @@ export function appendChild(
parentInstance.appendChild(child);
}

type DOMContainer =
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can also export this type from ReactDOM if that makes more sense.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Would make more sense than duplicating to me.

@@ -360,7 +368,7 @@ export function appendChildToContainer(
// event exists. So we wouldn't see it and dispatch it.
// This is why we ensure that containers have inline onclick defined.
// https://github.com/facebook/react/issues/11918
if (parentNode.onclick === null) {
if (!container._reactRootContainer && parentNode.onclick === null) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Compare to null and undefined explicitly, plz

@@ -360,7 +368,7 @@ export function appendChildToContainer(
// event exists. So we wouldn't see it and dispatch it.
// This is why we ensure that containers have inline onclick defined.
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we modify the comments together?

// https://github.com/facebook/react/issues/11918
if (!container._reactRootContainer && parentNode.onclick === null) {
const {_reactRootContainer} = container;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Another style nit: we don't use destructuring, with some exceptions like module-style objects or function args (component props).

}

ReactDOM.render(<Component />, container);
expect(typeof portalContainer.onclick === 'function').toBeTruthy();
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 just do expect(typeof ...).toBe('function'). Not that it matters.

Copy link
Collaborator

@gaearon gaearon left a comment

Choose a reason for hiding this comment

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

Feel free to merge

@gaearon
Copy link
Collaborator

gaearon commented Oct 9, 2018

(see nit in #13778 (comment))

@philipp-spiess philipp-spiess merged commit f47a958 into facebook:master Oct 9, 2018
@philipp-spiess philipp-spiess deleted the ios-tap-highlight branch October 9, 2018 08:27
linjiajian999 pushed a commit to linjiajian999/react that referenced this pull request Oct 22, 2018
Fixes facebook#13777

As part of facebook#11927 we introduced a regression by adding onclick handler
to the React root. This causes the whole React tree to flash when tapped
on iOS devices (for reasons I outlined in
facebook#12989 (comment)).

To fix this, we should only apply onclick listeners to portal roots. I
verified that my proposed fix indeed works by checking out our DOM
fixtures and adding regression tests.

Strangely, I had to make changes to the DOM fixtures to see the behavior
in the first place. This seems to be caused by our normal sites (and 
thus their React root) being bigger than the viewport:

![](http://cl.ly/3f18f8b85e91/Screen%20Recording%202018-10-05%20at%2001.32%20AM.gif)

An alternative approach to finding out if we're appending to a React
root would be to add a third parameter to `appendChildToContainer` based
on the tag of the parent fiber.
@gaearon gaearon mentioned this pull request Oct 23, 2018
jetoneza pushed a commit to jetoneza/react that referenced this pull request Jan 23, 2019
Fixes facebook#13777

As part of facebook#11927 we introduced a regression by adding onclick handler
to the React root. This causes the whole React tree to flash when tapped
on iOS devices (for reasons I outlined in
facebook#12989 (comment)).

To fix this, we should only apply onclick listeners to portal roots. I
verified that my proposed fix indeed works by checking out our DOM
fixtures and adding regression tests.

Strangely, I had to make changes to the DOM fixtures to see the behavior
in the first place. This seems to be caused by our normal sites (and 
thus their React root) being bigger than the viewport:

![](http://cl.ly/3f18f8b85e91/Screen%20Recording%202018-10-05%20at%2001.32%20AM.gif)

An alternative approach to finding out if we're appending to a React
root would be to add a third parameter to `appendChildToContainer` based
on the tag of the parent fiber.
philipp-spiess added a commit to philipp-spiess/react that referenced this pull request Jan 23, 2019
Fixes facebook#14535
Alternative to facebook#13778

As @gaearon already noted, we can not rely on a container node having a
`_reactRootContainer` to detect a React Root since the `createRoot()`
API will not set it.

Furthermore, the `createRoot()` API is currently only setting a property
on the container in DEV mode.

We could:

 1. Set a property in prod as well.
 2. Pass in more information into the `appendChildToContainer()` config.

This PR is an attempt to implement 2. to visualize the outcome. It feels
bad to do this though since non of the other renderers need that
property and I’m not sure how stable the reconciler API is (i.e if we
can just add properties like this).

Let me know if you prefer 1. or have another idea. 🙂
philipp-spiess added a commit to philipp-spiess/react that referenced this pull request Jan 23, 2019
Fixes facebook#14535
Alternative to facebook#13778

As @gaearon already noted, we can not rely on a container node having a
`_reactRootContainer` to detect a React Root since the `createRoot()`
API will not set it.

Furthermore, the `createRoot()` API is currently only setting a property
on the container in DEV mode.

We could:

 1. Set a property in prod as well.
 2. Pass in more information into the `appendChildToContainer()` config.

This PR is an attempt to implement 2. to visualize the outcome. It feels
bad to do this though since non of the other renderers need that
property and I’m not sure how stable the reconciler API is (i.e if we
can just add properties like this).

Let me know if you prefer 1. or have another idea. 🙂
philipp-spiess added a commit to philipp-spiess/react that referenced this pull request Jan 24, 2019
Fixes facebook#14535
Related to facebook#13778
Alternative to facebook#14681

As @gaearon already noted, we can not rely on a container node having a
`_reactRootContainer` to detect a React Root since the `createRoot()`
API will not set it.

Furthermore, the `createRoot()` API is currently only setting a property
on the container in DEV mode.

We could:

 1. Set a property in prod as well.
 2. Pass in more information into the `appendChildToContainer()` config.

This PR is an attempt to implement 1. It feels better than [the other
approach](facebook#14681) since we don't
need to change the reconciler API.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

The gray overlay when tap the react root container
6 participants