-
Notifications
You must be signed in to change notification settings - Fork 270
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(web): invalidate position on ancestor scroll #472
Conversation
Fixes callstack#471. Added a test case to `example-web`.
//@ts-ignore | ||
window.addEventListener('resize', onResize); | ||
window.addEventListener('resize', invalidateContainerPosition); |
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.
@motiz88 you should probably subscribe to resize events the react-native way:
https://necolas.github.io/react-native-web/docs/use-window-dimensions/
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 use of the
resize
event was pre-existing and I had no intention of changing it as part of this bugfix. I merely renamedonResize
toinvalidateContainerPosition
to better communicate what it does (and reuse it in theonScroll
handler). - IMO, given this is platform-specific code, use of DOM primitives is completely fine. It's also not directly interchangeable with
useWindowDimensions
(which would tie us to the React component lifecycle in a way that might not be the most correct/efficient for this use case)
window.addEventListener('resize', onResize); | ||
window.addEventListener('resize', invalidateContainerPosition); | ||
//@ts-ignore | ||
document.addEventListener('scroll', onDocumentScroll, {capture: 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.
If there's no way to do this in a more react-native idiomatic way, my opinion would be to do something like the following at the top of the file:
// @ts-ignore
const { addEventListener, removeEventListener } = document;
...
const RCTSliderWebComponent = React.forwardRef(
...
);
That would reduce the overall number of @ts-ignore
comments in the code, which aren't ideal.
Perhaps it would be even better to create a unique hook (e.g. useOnDocumentScroll
that receives a callback or something), that abstracts this functionality.
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.
That would reduce the overall number of @ts-ignore comments in the code, which aren't ideal.
I think the @ts-ignore
issue (which, again, is pre-existing here) would be best solved by configuring TypeScript to properly typecheck uses of DOM APIs in .web.tsx
files. This might be solved by adding /// <reference lib="dom" />
to the top of the file, but I haven't tried it.
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.
@jspizziri I've put up #475 to deal with the @ts-ignore
s comprehensively.
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.
To me it looks very good, I'm happy to accept that. Also thanks so much for adding another example showing this specific scenario! 👍
@jspizziri Would it be possible for you to let us know if @motiz88's answers address your remarks? I don't want to merge something that still has some potentially open discussions.
@BartoszKlonowski LGTM! |
Summary:
Fixes #471.
As there is no native way to listen for changes to
getBoundingClientRect()
, the web implementation of Slider must cache and try to correctly invalidate the measurements. The code already does this on layout and when the viewport is resized, but not when the slider's bounding rect changes due to scrolling. This PR registers a capturingscroll
event handler ondocument
and invalidates the cache when an ancestor of the slider scrolls. This is probably not airtight (see this StackOverflow discussion) but is AFAICT correct.For performance, it may be worth experimenting with unregistering the
scroll
(andresize
) listener once the cache has been invalidated - this would avoid calling O(sliders on page) handlers on every frame while scrolling. This is a potentially more invasive change to Slider so I am publishing the PR without it.Test Plan:
Added an example to
example-web
and tested it manually (see video).Screen.Recording.2022-12-27.at.20.53.08.mov