mirror of
https://github.com/cheeaun/phanpy.git
synced 2025-02-24 00:38:49 +01:00
Further simplify the scrolling logic in Status page
Previous code is too darn complicated and doesn't work in async cases e.g. user scrolled while the status is loading
This commit is contained in:
parent
3506285176
commit
cab06ae936
1 changed files with 55 additions and 67 deletions
|
@ -55,7 +55,9 @@ function StatusPage({ id }) {
|
|||
};
|
||||
}, [id]);
|
||||
|
||||
const scrollOffsets = useRef();
|
||||
const initContext = () => {
|
||||
console.debug('initContext', id);
|
||||
setUIState('loading');
|
||||
let heroTimer;
|
||||
|
||||
|
@ -68,15 +70,15 @@ function StatusPage({ id }) {
|
|||
);
|
||||
setStatuses(reallyCachedStatuses);
|
||||
} else {
|
||||
const heroIndex = statuses.findIndex((s) => s.id === id);
|
||||
if (heroIndex !== -1) {
|
||||
// Case 2: It's in current statuses. Slice off all descendant statuses after the hero status to be safe
|
||||
const slicedStatuses = statuses.slice(0, heroIndex + 1);
|
||||
setStatuses(slicedStatuses);
|
||||
} else {
|
||||
// Case 3: Not cached and not in statuses, let's start from scratch
|
||||
setStatuses([{ id }]);
|
||||
}
|
||||
// const heroIndex = statuses.findIndex((s) => s.id === id);
|
||||
// if (heroIndex !== -1) {
|
||||
// // Case 2: It's in current statuses. Slice off all descendant statuses after the hero status to be safe
|
||||
// const slicedStatuses = statuses.slice(0, heroIndex + 1);
|
||||
// setStatuses(slicedStatuses);
|
||||
// } else {
|
||||
// Case 3: Not cached and not in statuses, let's start from scratch
|
||||
setStatuses([{ id }]);
|
||||
// }
|
||||
}
|
||||
|
||||
(async () => {
|
||||
|
@ -86,17 +88,7 @@ function StatusPage({ id }) {
|
|||
const hasStatus = !!snapStates.statuses[id];
|
||||
let heroStatus = snapStates.statuses[id];
|
||||
if (hasStatus) {
|
||||
console.log('Hero status is cached');
|
||||
// NOTE: This might conflict if the user interacts with the status before the fetch is done, e.g. favouriting it
|
||||
// heroTimer = setTimeout(async () => {
|
||||
// try {
|
||||
// heroStatus = await heroFetch();
|
||||
// states.statuses[id] = heroStatus;
|
||||
// } catch (e) {
|
||||
// // Silent fail if status is cached
|
||||
// console.error(e);
|
||||
// }
|
||||
// }, 1000);
|
||||
console.debug('Hero status is cached');
|
||||
} else {
|
||||
try {
|
||||
heroStatus = await heroFetch();
|
||||
|
@ -162,6 +154,10 @@ function StatusPage({ id }) {
|
|||
];
|
||||
|
||||
setUIState('default');
|
||||
scrollOffsets.current = {
|
||||
offsetTop: heroStatusRef.current?.offsetTop,
|
||||
scrollTop: scrollableRef.current?.scrollTop,
|
||||
};
|
||||
console.log({ allStatuses });
|
||||
setStatuses(allStatuses);
|
||||
store.session.setJSON('statuses-' + id, allStatuses);
|
||||
|
@ -177,8 +173,40 @@ function StatusPage({ id }) {
|
|||
};
|
||||
|
||||
useEffect(initContext, [id]);
|
||||
useEffect(() => {
|
||||
if (!statuses.length) return;
|
||||
const scrollPosition = states.scrollPositions[id];
|
||||
console.debug('scrollPosition', scrollPosition);
|
||||
if (!userInitiated.current && !!scrollPosition) {
|
||||
console.debug('Case 1', {
|
||||
userInitiated: userInitiated.current,
|
||||
scrollPosition,
|
||||
});
|
||||
scrollableRef.current.scrollTop = scrollPosition;
|
||||
} else if (scrollOffsets.current) {
|
||||
const newScrollOffsets = {
|
||||
offsetTop: heroStatusRef.current?.offsetTop,
|
||||
scrollTop: scrollableRef.current?.scrollTop,
|
||||
};
|
||||
const newScrollTop =
|
||||
newScrollOffsets.offsetTop - scrollOffsets.current.offsetTop;
|
||||
console.debug('Case 2', {
|
||||
userInitiated: userInitiated.current,
|
||||
scrollOffsets: scrollOffsets.current,
|
||||
newScrollOffsets,
|
||||
newScrollTop,
|
||||
statuses: [...statuses],
|
||||
});
|
||||
scrollableRef.current.scrollTop = newScrollTop;
|
||||
}
|
||||
|
||||
// Reset
|
||||
userInitiated.current = false;
|
||||
scrollOffsets.current = null;
|
||||
}, [statuses]);
|
||||
|
||||
useEffect(() => {
|
||||
if (snapStates.reloadStatusPage <= 0) return;
|
||||
// Delete the cache for the context
|
||||
(async () => {
|
||||
try {
|
||||
|
@ -199,53 +227,13 @@ function StatusPage({ id }) {
|
|||
})();
|
||||
}, [snapStates.reloadStatusPage]);
|
||||
|
||||
const firstLoad = useRef(true);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!statuses.length) return;
|
||||
const isLoading = uiState === 'loading';
|
||||
if (userInitiated.current) {
|
||||
const hasAncestors = statuses.findIndex((s) => s.id === id) > 0; // Cannot use `ancestor` key because the hero state is dynamic
|
||||
if (!isLoading && hasAncestors) {
|
||||
// Case 1: User initiated, has ancestors, after statuses are loaded, SNAP to hero status
|
||||
console.log('Case 1');
|
||||
heroStatusRef.current?.scrollIntoView();
|
||||
} else if (isLoading && statuses.length > 1) {
|
||||
if (firstLoad.current) {
|
||||
// Case 2.1: User initiated, first load, don't smooth scroll anything
|
||||
console.log('Case 2.1');
|
||||
heroStatusRef.current?.scrollIntoView();
|
||||
} else {
|
||||
// Case 2.2: User initiated, while statuses are loading, SMOOTH-SCROLL to hero status
|
||||
console.log('Case 2.2');
|
||||
heroStatusRef.current?.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start',
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const scrollPosition = states.scrollPositions[id];
|
||||
if (scrollPosition && scrollableRef.current) {
|
||||
// Case 3: Not user initiated (e.g. back/forward button), restore to saved scroll position
|
||||
console.log('Case 3');
|
||||
scrollableRef.current.scrollTop = scrollPosition;
|
||||
}
|
||||
}
|
||||
console.log('No case', {
|
||||
isLoading,
|
||||
userInitiated: userInitiated.current,
|
||||
statusesLength: statuses.length,
|
||||
firstLoad: firstLoad.current,
|
||||
// scrollPosition,
|
||||
});
|
||||
|
||||
if (!isLoading) {
|
||||
// Reset user initiated flag after statuses are loaded
|
||||
userInitiated.current = false;
|
||||
firstLoad.current = false;
|
||||
}
|
||||
}, [statuses, uiState]);
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
// clear all scrollPositions
|
||||
states.scrollPositions = {};
|
||||
states.reloadStatusPage = 0;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const heroStatus = snapStates.statuses[id];
|
||||
const heroDisplayName = useMemo(() => {
|
||||
|
|
Loading…
Reference in a new issue