-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[Security Solution][Resolver] Update the resolver element ref on scroll events if the position of the element has changed within the page #72461
Conversation
…he element has changed within the page
Pinging @elastic/endpoint-app-team (Feature:Endpoint) |
Pinging @elastic/endpoint-data-visibility-team (Team:Endpoint Data Visibility) |
useEffect(() => { | ||
window.addEventListener('scroll', handleScroll, { passive: true }); | ||
return () => { | ||
window.removeEventListener('scroll', handleScroll); |
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.
(edit) ❔ I think you might also need to supply { passive: true }
here for it to treat it as a "matching" signature and do the removal? I'll test and get back to you in a sec on that.
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.
no, passive is only a possible value for the options object in addEventListener, not removeEventListener
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.
OK, nevermind looks like that's just for useCapture
/ {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.
The advice for this on MDN reads as:
It's worth noting that some browser releases have been inconsistent on this, and unless you have specific reasons otherwise, it's probably wise to use the same values used for the call to addEventListener() when calling removeEventListener().
https://wiki.developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
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.
You can leave this one be. I'm not sure how relevant that advice on MDN is anymore - probably "not very".
const ref = useCallback((node: Element | null) => { | ||
setCurrentNode(node); | ||
if (node !== null) { | ||
setRect(node.getBoundingClientRect()); | ||
} | ||
}, []); | ||
const { ResizeObserver } = useContext(SideEffectContext); | ||
const handleScroll = useCallback(() => { | ||
if (currentX !== window.scrollX || currentY !== window.scrollY) { |
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 want to wrap this in a requestAnimationFrame b/c I think when you query scrollX
, scrollY
, and getBoundingClientRect
it forces layout sync
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.
re: scrollX
, scrollY
, getBoundingClientRect
:
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.
Is it possible useCallback
already does this for you under the hood? Seems like something @oatkiller would know.
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.
@bkimmel can you explain how running that in raf would help?
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.
Reading scrollX
, scrollY
and getBoundingClientRect
all force sync layout according to: https://gist.github.com/paulirish/5d52fb081b3570c81e3a Since while this is scrolling, it will get called rapidly, wrapping it in a rAF may reduce layout thrashing. Otherwise it seems like we'd be in a tight loop of this code forcing layout calculations and changing them in quick succession. The rAF
doesn't solve everything, but it at least aligns the queries on scrollX etc. until after the current layout has been calculated... so I'd expect it to be at least a little better. Is there a reason you know of or something I'm missing that would make it OK in this case?
Finished review: 1 🔴 and 1 ❔ / discussion. I'm on track for a thumb here the 🔴 is addressed. |
@@ -284,14 +284,30 @@ export function useAutoUpdatingClientRect(): [DOMRect | null, (node: Element | n | |||
const [rect, setRect] = useState<DOMRect | null>(null); | |||
// Using state as ref.current update does not trigger effect hook when reset | |||
const [currentNode, setCurrentNode] = useState<Element | null>(null); | |||
|
|||
const [currentY, setCurrentY] = useState<number>(0); |
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.
should you initialize this to the value by reading it from the dom?
const [currentY, setCurrentY] = useState<number>(() => window.scrollY);
const [currentX, setCurrentX] = useState<number>(() => window.scrollX);
if (currentX !== window.scrollX || currentY !== window.scrollY) { | ||
if (currentNode !== null) { | ||
setRect(currentNode.getBoundingClientRect()); | ||
setCurrentY(window.scrollY); |
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.
do you need to use state for currentY
and currentX
? If they change but setRect
doesn't, there shouldn't be any need to render right?
how about making it like:
// assuming currentY and currentX are now refs
currentY.current = window.scrollY
currentX.current = window.scrollX
setRect(currentNode.getBoundingClientRect());
const ref = useCallback((node: Element | null) => { | ||
setCurrentNode(node); | ||
if (node !== null) { | ||
setRect(node.getBoundingClientRect()); | ||
} | ||
}, []); | ||
const { ResizeObserver } = useContext(SideEffectContext); | ||
const handleScroll = useCallback(() => { | ||
if (currentX !== window.scrollX || currentY !== window.scrollY) { |
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.
@bkimmel can you explain how running that in raf would help?
const currentY = window.scrollY; | ||
|
||
if (currentNode !== null && (previousX !== currentX || previousY !== currentY)) { | ||
setRect(currentNode.getBoundingClientRect()); |
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.
future improvement: you could check that the new DOMRect is different before setting it. this would prevent useless rerenders.
💚 Build SucceededBuild metricsasync chunks size
History
To update your PR or re-run it, just comment with: |
* master: (28 commits) allow some env settings for ingest manager (elastic#72544) Add inspector for VEGA (elastic#70941) chore(NA): fix grunt task for test:coverage (elastic#72539) Archive e2e test results in ES (elastic#72575) preserve 401 errors from new es client (elastic#71248) [SIEM][Detections] Updates text for severity and risk_score overrides (elastic#72244) fixing error occurences tooltip (elastic#72425) use KibanaClient interface instead of Client for new client interface (elastic#72388) [APM] Handle ML errors (elastic#72316) [Discover] Improve histogram tests (elastic#72235) [ftr/webdriver] retry on all errors, use Rx so that timers are canceled (elastic#72540) [pre-req] Move .storybook to storybook; standardize files (elastic#72384) [Security_Solution][Resolver][Bug]: Restore breadcrumb background (elastic#72538) [ML] Fix annotation detector linking & delayed_data(0) (elastic#72468) [Security Solution][Exceptions] - Make esTypes and subType available to index patterns (elastic#72336) [SIEM] Uses faster wait from testing-library and removes duplicate older wait idiom (elastic#72509) Fix long combo box items breaking out of flex item width (elastic#72512) [pipeline/commitStatus] update commit status in baseline-capture job (elastic#72366) [Security Solution][Resolver] Update the resolver element ref on scroll events if the position of the element has changed within the page (elastic#72461) [Maps] auto-fit to data bounds (elastic#72129) ...
Summary
Fixes an issue in the useCamera hook where the useAutoUpdatingClientRect hook returned a reference to the resolver dom element that was stale, namely the top/y & left/x properties that are used by the zoom action.
BEFORE:
AFTER:
For maintainers