mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
perf(replies): progressive render, 500 replies/page, content-visibility
Set repliesPerPage to 500 to avoid Virtuoso pagination sort drift. Add useProgressiveRender with startTransition batching and CSS content-visibility for long reply lists.
This commit is contained in:
@@ -43,6 +43,8 @@ import usePostNumberStore from '../../stores/use-post-number-store';
|
||||
import { alertChallengeVerificationFailed } from '../../lib/utils/challenge-utils';
|
||||
import { usePublishCommentModeration } from '@plebbit/plebbit-react-hooks';
|
||||
import useQuotedByMap from '../../hooks/use-quoted-by-map';
|
||||
import useProgressiveRender from '../../hooks/use-progressive-render';
|
||||
import { REPLIES_PER_PAGE } from '../../lib/constants';
|
||||
|
||||
const { addChallenge } = useChallengesStore.getState();
|
||||
|
||||
@@ -674,6 +676,7 @@ const PostDesktop = ({
|
||||
comment: post,
|
||||
sortType: 'old',
|
||||
flat: true,
|
||||
repliesPerPage: REPLIES_PER_PAGE,
|
||||
accountComments: { newerThan: Infinity, append: true },
|
||||
});
|
||||
const { replies, hasMore, loadMore } = repliesResult;
|
||||
@@ -737,6 +740,13 @@ const PostDesktop = ({
|
||||
|
||||
const quotedByMap = useQuotedByMap(filteredReplies);
|
||||
|
||||
const visibleReplies = useProgressiveRender(filteredReplies, {
|
||||
batchSize: 50,
|
||||
intervalMs: 100,
|
||||
resetKey: cid,
|
||||
disabled: hasMore || !!targetReplyCid || !showAllReplies,
|
||||
});
|
||||
|
||||
// Virtuoso scroll position management for infinite replies
|
||||
const virtuosoRef = useRef<VirtuosoHandle | null>(null);
|
||||
const virtuosoStateKey = `replies-desktop-${cid}`;
|
||||
@@ -888,7 +898,7 @@ const PostDesktop = ({
|
||||
!isInPendingPostView &&
|
||||
showReplies &&
|
||||
!hasMore &&
|
||||
filteredReplies.map((reply, index) => (
|
||||
visibleReplies.map((reply, index) => (
|
||||
<div key={index} className={styles.replyContainer}>
|
||||
<Reply
|
||||
reply={reply}
|
||||
|
||||
@@ -37,6 +37,8 @@ import useFeedResetStore from '../../stores/use-feed-reset-store';
|
||||
import usePostNumberStore from '../../stores/use-post-number-store';
|
||||
import { alertChallengeVerificationFailed } from '../../lib/utils/challenge-utils';
|
||||
import useQuotedByMap from '../../hooks/use-quoted-by-map';
|
||||
import useProgressiveRender from '../../hooks/use-progressive-render';
|
||||
import { REPLIES_PER_PAGE } from '../../lib/constants';
|
||||
|
||||
const { addChallenge } = useChallengesStore.getState();
|
||||
|
||||
@@ -497,6 +499,7 @@ const PostMobile = ({
|
||||
comment: post,
|
||||
sortType: 'old',
|
||||
flat: true,
|
||||
repliesPerPage: REPLIES_PER_PAGE,
|
||||
accountComments: { newerThan: Infinity, append: true },
|
||||
});
|
||||
const { replies, hasMore, loadMore } = repliesResult;
|
||||
@@ -537,6 +540,13 @@ const PostMobile = ({
|
||||
|
||||
const quotedByMap = useQuotedByMap(filteredReplies);
|
||||
|
||||
const visibleReplies = useProgressiveRender(filteredReplies, {
|
||||
batchSize: 50,
|
||||
intervalMs: 100,
|
||||
resetKey: cid,
|
||||
disabled: hasMore || !!targetReplyCid || !showAllReplies,
|
||||
});
|
||||
|
||||
// Virtuoso scroll position management for infinite replies
|
||||
const virtuosoRef = useRef<VirtuosoHandle | null>(null);
|
||||
const virtuosoStateKey = `replies-mobile-${cid}`;
|
||||
@@ -670,7 +680,7 @@ const PostMobile = ({
|
||||
!isInPendingPostView &&
|
||||
showReplies &&
|
||||
!hasMore &&
|
||||
filteredReplies.map((reply, index) => (
|
||||
visibleReplies.map((reply, index) => (
|
||||
<div key={index} className={styles.replyContainer}>
|
||||
<Reply postReplyCount={replyCount} reply={reply} roles={roles} threadNumber={post?.number} quotedByMap={quotedByMap} />
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import { startTransition, useEffect, useState } from 'react';
|
||||
|
||||
interface UseProgressiveRenderOptions {
|
||||
batchSize?: number;
|
||||
intervalMs?: number;
|
||||
resetKey?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_BATCH_SIZE = 50;
|
||||
const DEFAULT_INTERVAL_MS = 100;
|
||||
|
||||
/**
|
||||
* Progressively reveals items in batches via startTransition to avoid blocking the UI
|
||||
* when mounting many heavy components (e.g. 500 reply components).
|
||||
* When disabled or once fully caught up, returns the full array immediately.
|
||||
*/
|
||||
const useProgressiveRender = <T>(items: T[], options: UseProgressiveRenderOptions = {}): T[] => {
|
||||
const { batchSize = DEFAULT_BATCH_SIZE, intervalMs = DEFAULT_INTERVAL_MS, resetKey, disabled = false } = options;
|
||||
|
||||
const [progressState, setProgressState] = useState<{ key: string | undefined; visibleCount: number }>({
|
||||
key: resetKey,
|
||||
visibleCount: batchSize,
|
||||
});
|
||||
const isResetKeyChanged = progressState.key !== resetKey;
|
||||
const visibleCount = isResetKeyChanged ? batchSize : progressState.visibleCount;
|
||||
|
||||
useEffect(() => {
|
||||
if (disabled || items.length <= batchSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
const current = visibleCount >= items.length ? items.length : visibleCount;
|
||||
if (current >= items.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const next = Math.min(current + batchSize, items.length);
|
||||
const timer = window.setTimeout(() => {
|
||||
startTransition(() => {
|
||||
setProgressState({
|
||||
key: resetKey,
|
||||
visibleCount: next,
|
||||
});
|
||||
});
|
||||
}, intervalMs);
|
||||
|
||||
return () => window.clearTimeout(timer);
|
||||
}, [items.length, visibleCount, batchSize, intervalMs, disabled, resetKey]);
|
||||
|
||||
if (disabled || items.length <= batchSize) {
|
||||
return items;
|
||||
}
|
||||
|
||||
if (visibleCount >= items.length) {
|
||||
return items;
|
||||
}
|
||||
|
||||
return items.slice(0, visibleCount);
|
||||
};
|
||||
|
||||
export default useProgressiveRender;
|
||||
@@ -0,0 +1,2 @@
|
||||
/** Max replies loaded per page from useReplies. Threads with > this use Virtuoso. */
|
||||
export const REPLIES_PER_PAGE = 500;
|
||||
@@ -456,6 +456,8 @@
|
||||
|
||||
.replyDesktop {
|
||||
padding-top: 4px;
|
||||
content-visibility: auto;
|
||||
contain-intrinsic-size: auto 120px;
|
||||
}
|
||||
|
||||
.replyDesktop .sideArrows {
|
||||
@@ -490,6 +492,8 @@
|
||||
|
||||
.replyMobile {
|
||||
padding-top: 7px;
|
||||
content-visibility: auto;
|
||||
contain-intrinsic-size: auto 120px;
|
||||
}
|
||||
|
||||
.replyMobile .replyContainer {
|
||||
|
||||
Reference in New Issue
Block a user