fix: reset board scroll on link nav

Force scroll-to-top on link navigation while keeping POP restores, and scope Virtuoso keys per pathname to avoid cross-board scroll leakage.
This commit is contained in:
plebeius
2025-12-08 13:03:25 +01:00
parent 6f1fcafc2c
commit 9e13292ae3
2 changed files with 36 additions and 8 deletions
+18 -4
View File
@@ -1,5 +1,5 @@
import { useEffect, useMemo, useRef, useState } from 'react';
import { Link, useLocation, useParams } from 'react-router-dom';
import { Link, useLocation, useNavigationType, useParams } from 'react-router-dom';
import { Comment, useAccount, useAccountComments, useAccountSubplebbits, useBlock, useFeed, useSubplebbit } from '@plebbit/plebbit-react-hooks';
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
import { Trans, useTranslation } from 'react-i18next';
@@ -274,19 +274,33 @@ const Board = () => {
// save the last Virtuoso state to restore it when navigating back
const virtuosoRef = useRef<VirtuosoHandle | null>(null);
// include pathname in key so each board has its own scroll state
const virtuosoStateKey = `${location.pathname}-${sortType}-${timeFilterSeconds}`;
const navigationType = useNavigationType();
// When entering a board via link (PUSH/REPLACE), force scroll to top to avoid inheriting prior view scroll.
useEffect(() => {
if (navigationType !== 'POP') {
window.scrollTo({ top: 0, left: 0, behavior: 'auto' });
}
}, [navigationType, location.pathname]);
useEffect(() => {
// capture the key at effect creation time to prevent race conditions during navigation
const currentKey = virtuosoStateKey;
const setLastVirtuosoState = () => {
virtuosoRef.current?.getState((snapshot: StateSnapshot) => {
if (snapshot?.ranges?.length) {
lastVirtuosoStates[sortType + timeFilterSeconds] = snapshot;
lastVirtuosoStates[currentKey] = snapshot;
}
});
};
window.addEventListener('scroll', setLastVirtuosoState);
return () => window.removeEventListener('scroll', setLastVirtuosoState);
}, [sortType, timeFilterSeconds]);
}, [virtuosoStateKey]);
const lastVirtuosoState = lastVirtuosoStates?.[sortType + timeFilterSeconds];
// only restore scroll state on back/forward navigation (POP), not when clicking links (PUSH)
const lastVirtuosoState = navigationType === 'POP' ? lastVirtuosoStates?.[virtuosoStateKey] : undefined;
useEffect(() => {
const boardTitle = title ? title : shortAddress || subplebbitAddress;
+18 -4
View File
@@ -1,5 +1,5 @@
import { useEffect, useMemo, useRef, useState, useCallback } from 'react';
import { Link, useLocation, useParams } from 'react-router-dom';
import { Link, useLocation, useNavigationType, useParams } from 'react-router-dom';
import { Trans, useTranslation } from 'react-i18next';
import { Comment, useAccount, useFeed, useSubplebbit, useBlock, useAccountComments } from '@plebbit/plebbit-react-hooks';
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
@@ -452,18 +452,32 @@ const Catalog = () => {
// save the last Virtuoso state to restore it when navigating back
const virtuosoRef = useRef<VirtuosoHandle | null>(null);
// include pathname in key so each board has its own scroll state
const virtuosoStateKey = `${location.pathname}-${sortType}-${timeFilterSeconds}-catalog`;
const navigationType = useNavigationType();
// When entering a board via link (PUSH/REPLACE), force scroll to top to avoid inheriting prior view scroll.
useEffect(() => {
if (navigationType !== 'POP') {
window.scrollTo({ top: 0, left: 0, behavior: 'auto' });
}
}, [navigationType, location.pathname]);
useEffect(() => {
// capture the key at effect creation time to prevent race conditions during navigation
const currentKey = virtuosoStateKey;
const setLastVirtuosoState = () =>
virtuosoRef.current?.getState((snapshot: StateSnapshot) => {
if (snapshot?.ranges?.length) {
lastVirtuosoStates[sortType + timeFilterSeconds + 'catalog'] = snapshot;
lastVirtuosoStates[currentKey] = snapshot;
}
});
window.addEventListener('scroll', setLastVirtuosoState);
return () => window.removeEventListener('scroll', setLastVirtuosoState);
}, [sortType, timeFilterSeconds]);
}, [virtuosoStateKey]);
const lastVirtuosoState = lastVirtuosoStates?.[sortType + timeFilterSeconds + 'catalog'];
// only restore scroll state on back/forward navigation (POP), not when clicking links (PUSH)
const lastVirtuosoState = navigationType === 'POP' ? lastVirtuosoStates?.[virtuosoStateKey] : undefined;
useEffect(() => {
let documentTitle = title ? title : shortAddress;