Fix race condition in Timeline

This commit is contained in:
Fedor Indutny 2022-03-16 14:07:53 -07:00 committed by GitHub
parent 5a7196e464
commit a9bf0cc0c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 25 additions and 1 deletions

View File

@ -272,6 +272,7 @@ export class Timeline extends React.Component<
private readonly atBottomDetectorRef = React.createRef<HTMLDivElement>();
private readonly lastSeenIndicatorRef = React.createRef<HTMLDivElement>();
private intersectionObserver?: IntersectionObserver;
private intersectionObserverCallbackFrame?: number;
// This is a best guess. It will likely be overridden when the timeline is measured.
private maxVisibleRows = Math.ceil(window.innerHeight / MIN_ROW_HEIGHT);
@ -405,6 +406,10 @@ export class Timeline extends React.Component<
// this another way, but this approach works.)
this.intersectionObserver?.disconnect();
if (this.intersectionObserverCallbackFrame !== undefined) {
window.cancelAnimationFrame(this.intersectionObserverCallbackFrame);
}
const intersectionRatios = new Map<Element, number>();
const intersectionObserverCallback: IntersectionObserverCallback =
@ -495,7 +500,26 @@ export class Timeline extends React.Component<
};
this.intersectionObserver = new IntersectionObserver(
intersectionObserverCallback,
(entries, observer) => {
assert(
this.intersectionObserver === observer,
'observer.disconnect() should prevent callbacks from firing'
);
// `react-measure` schedules the callbacks on the next tick and so
// should we because we want other parts of this component to respond
// to resize events before we recalculate what is visible.
this.intersectionObserverCallbackFrame = window.requestAnimationFrame(
() => {
// Observer was updated from under us
if (this.intersectionObserver !== observer) {
return;
}
intersectionObserverCallback(entries, observer);
}
);
},
{
root: containerEl,
threshold: [0, 1],