fix(plex): infinite-scroll dead after drill-in → Back (stale sentinel observer)
The unified-library grid unmounts when you open an item's info/show/season page and remounts as a NEW element on Back. The IntersectionObserver effect keyed only on [hasNextPage, isFetchingNextPage, fetchNextPage] — none of which change across a pure navigation — so it never re-ran: the observer kept watching the detached old sentinel node and fetchNextPage never fired again, leaving the feed frozen at the already-loaded pages (e.g. 80/1227) even though more exist. Intermittent because a coincident isFetchingNextPage toggle around the nav could re-run the effect. Fix: observe via a callback ref (state) instead of useRef, so the effect re-runs on every sentinel mount/unmount and always watches the live node.
This commit is contained in:
parent
28061353ec
commit
8cbaf1d731
1 changed files with 10 additions and 7 deletions
|
|
@ -156,21 +156,24 @@ export default function PlexBrowse({
|
|||
// Episode matches (grouped "Episodes" section) — search-only; same set on every page, take page 0.
|
||||
const episodes = browseQ.data?.pages[0]?.episodes ?? [];
|
||||
|
||||
// Infinite scroll: auto-load the next page when the sentinel scrolls into view.
|
||||
const sentinel = useRef<HTMLDivElement>(null);
|
||||
// Infinite scroll: auto-load the next page when the sentinel scrolls into view. The sentinel lives
|
||||
// in the grid branch, which UNMOUNTS when we drill into an info/show/season page and remounts on
|
||||
// Back — as a NEW element. A callback ref (state, not useRef) re-runs this effect on every
|
||||
// mount/unmount, so the observer always watches the live node; a plain ref would keep observing the
|
||||
// detached old node after Back and never fire fetchNextPage again (feed stuck at the loaded pages).
|
||||
const [sentinelEl, setSentinelEl] = useState<HTMLDivElement | null>(null);
|
||||
const { hasNextPage, isFetchingNextPage, fetchNextPage } = browseQ;
|
||||
useEffect(() => {
|
||||
const el = sentinel.current;
|
||||
if (!el) return;
|
||||
if (!sentinelEl) return;
|
||||
const io = new IntersectionObserver(
|
||||
(entries) => {
|
||||
if (entries[0].isIntersecting && hasNextPage && !isFetchingNextPage) fetchNextPage();
|
||||
},
|
||||
{ rootMargin: "600px" },
|
||||
);
|
||||
io.observe(el);
|
||||
io.observe(sentinelEl);
|
||||
return () => io.disconnect();
|
||||
}, [hasNextPage, isFetchingNextPage, fetchNextPage]);
|
||||
}, [sentinelEl, hasNextPage, isFetchingNextPage, fetchNextPage]);
|
||||
|
||||
function onCard(card: PlexCard) {
|
||||
scrollRef.current = scroller()?.scrollTop ?? 0; // remember grid position for the trip back
|
||||
|
|
@ -345,7 +348,7 @@ export default function PlexBrowse({
|
|||
</>
|
||||
)}
|
||||
|
||||
<div ref={sentinel} className="h-8" />
|
||||
<div ref={setSentinelEl} className="h-8" />
|
||||
{isFetchingNextPage && <p className="text-center text-xs text-muted pb-4">{t("plex.loading")}</p>}
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue