Fix linked-comment scrolling (again)
## Issue Now that we batch-resolve the comment authors before displaying the comments, the linked-comment scrolling logic didn't work well with nested replies. ## Change Previously, I didn't want to put the logic at the lowest level (`Comment`) because it was hard for the child to know whether to scroll or not. For example, we don't want to scroll when user changes the comment filters or presses the Refresh Comments button. Relented and moved the logic to `Comment`, and pass a flag via `window` (I know this is frowned upon by some) to indicate whether a scrolling is needed. This is probably more efficient overall as we don't need to scan the DOM, and with minimal delay as we scroll immediately after the linked-comment is mounted. ## Known issues In markdown posts with lots of images, a layout shift due to delayed inline-image fetching can cause the scrolling to be inaccurate. This should be fixed by reserving space for markdown post images.
This commit is contained in:
parent
0b0f2848da
commit
91be939c19
2 changed files with 21 additions and 19 deletions
|
@ -117,6 +117,7 @@ function Comment(props: Props) {
|
|||
location: { pathname, search },
|
||||
} = useHistory();
|
||||
|
||||
const isLinkedComment = linkedCommentId && linkedCommentId === commentId;
|
||||
const isInLinkedCommentChain =
|
||||
linkedCommentId &&
|
||||
linkedCommentAncestors[linkedCommentId] &&
|
||||
|
@ -205,6 +206,18 @@ function Comment(props: Props) {
|
|||
replace(`${pathname}?${urlParams.toString()}`);
|
||||
}
|
||||
|
||||
const linkedCommentRef = React.useCallback((node) => {
|
||||
if (node !== null && window.pendingLinkedCommentScroll) {
|
||||
const ROUGH_HEADER_HEIGHT = 125; // @see: --header-height
|
||||
delete window.pendingLinkedCommentScroll;
|
||||
window.scrollTo({
|
||||
top: node.getBoundingClientRect().top + window.scrollY - ROUGH_HEADER_HEIGHT,
|
||||
left: 0,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<li
|
||||
className={classnames('comment', {
|
||||
|
@ -215,8 +228,9 @@ function Comment(props: Props) {
|
|||
id={commentId}
|
||||
>
|
||||
<div
|
||||
ref={isLinkedComment ? linkedCommentRef : undefined}
|
||||
className={classnames('comment__content', {
|
||||
[COMMENT_HIGHLIGHTED]: linkedCommentId && linkedCommentId === commentId,
|
||||
[COMMENT_HIGHLIGHTED]: isLinkedComment,
|
||||
'comment--slimed': slimedToDeath && !displayDeadComment,
|
||||
})}
|
||||
>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// @flow
|
||||
import { COMMENT_HIGHLIGHTED } from 'constants/classnames';
|
||||
import { COMMENT_PAGE_SIZE_TOP_LEVEL, SORT_BY } from 'constants/comment';
|
||||
import { ENABLE_COMMENT_REACTIONS } from 'config';
|
||||
import { getChannelIdFromClaim } from 'util/claim';
|
||||
|
@ -15,7 +14,6 @@ import debounce from 'util/debounce';
|
|||
import Empty from 'component/common/empty';
|
||||
import React, { useEffect } from 'react';
|
||||
import Spinner from 'component/spinner';
|
||||
import useFetched from 'effects/use-fetched';
|
||||
import usePersistedState from 'effects/use-persisted-state';
|
||||
|
||||
const DEBOUNCE_SCROLL_HANDLER_MS = 200;
|
||||
|
@ -68,7 +66,6 @@ function CommentList(props: Props) {
|
|||
claimIsMine,
|
||||
myChannels,
|
||||
isFetchingComments,
|
||||
isFetchingCommentsById,
|
||||
isFetchingReacts,
|
||||
linkedCommentId,
|
||||
totalComments,
|
||||
|
@ -93,9 +90,6 @@ function CommentList(props: Props) {
|
|||
const [sort, setSort] = usePersistedState('comment-sort-by', DEFAULT_SORT);
|
||||
const [page, setPage] = React.useState(0);
|
||||
const [commentsToDisplay, setCommentsToDisplay] = React.useState(topLevelComments);
|
||||
const fetchedCommentsOnce = useFetched(isFetchingComments);
|
||||
const fetchedReactsOnce = useFetched(isFetchingReacts);
|
||||
const fetchedLinkedComment = useFetched(isFetchingCommentsById);
|
||||
const hasDefaultExpansion = commentsAreExpanded || desktopView;
|
||||
const [expandedComments, setExpandedComments] = React.useState(hasDefaultExpansion);
|
||||
const totalFetchedComments = allCommentIds ? allCommentIds.length : 0;
|
||||
|
@ -176,19 +170,13 @@ function CommentList(props: Props) {
|
|||
|
||||
// Scroll to linked-comment
|
||||
useEffect(() => {
|
||||
if (fetchedLinkedComment && fetchedCommentsOnce && fetchedReactsOnce) {
|
||||
const elems = document.getElementsByClassName(COMMENT_HIGHLIGHTED);
|
||||
if (elems.length > 0) {
|
||||
const ROUGH_HEADER_HEIGHT = 125; // @see: --header-height
|
||||
const linkedComment = elems[0];
|
||||
window.scrollTo({
|
||||
top: linkedComment.getBoundingClientRect().top + window.scrollY - ROUGH_HEADER_HEIGHT,
|
||||
left: 0,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
if (linkedCommentId) {
|
||||
window.pendingLinkedCommentScroll = true;
|
||||
} else {
|
||||
delete window.pendingLinkedCommentScroll;
|
||||
}
|
||||
}
|
||||
}, [fetchedLinkedComment, fetchedCommentsOnce, fetchedReactsOnce]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// Infinite scroll
|
||||
useEffect(() => {
|
||||
|
|
Loading…
Reference in a new issue