perf(board): reduce desktop reverse-scroll jank on /all

Apply the asymmetric viewport buffer that already fixed mobile to desktop
multiboard feeds, and trim per-post mount cost so remounts during scroll-up
are cheaper:

- Desktop multiboard buffer goes from {600,600} to {1200,2400} (top-heavy),
  matching the mobile pattern from 99c0bbfac so items stay mounted longer
  when scrolling back up
- Cache feed post height estimate by CID in pretext-height-estimates so
  remounts skip the Pretext text-measurement work
- Memoize CommentMedia and switch its expanded-media-store reads to atomic
  selectors so it stops rerendering on unrelated store changes
- Memoize useCommentMediaInfo return so its reference is stable for memo
  comparators downstream
- Stop useFetchGifFirstFrame from forcing an extra render on every post
  mount by bailing out of equivalent setState calls
- Extract PendingModerationActions out of PostInfo so the two
  usePublishCommentModeration calls only run on the post page when
  mod-approval is actually pending, not on every feed item
This commit is contained in:
Tommaso Casaburi
2026-04-18 13:31:02 +07:00
parent d07f5b3962
commit e161606147
8 changed files with 228 additions and 142 deletions
+12 -13
View File
@@ -1,4 +1,4 @@
import { useState, useEffect } from 'react';
import { useMemo, useState, useEffect } from 'react';
import { useLocation, useParams } from 'react-router-dom';
import { getCommentMediaInfo, fetchWebpageThumbnailIfNeeded, CommentMediaInfo } from '../lib/utils/media-utils';
import { isPendingPostView, isPostPageView } from '../lib/utils/view-utils';
@@ -65,16 +65,15 @@ export const useCommentMediaInfo = (link: string, thumbnailUrl: string, linkWidt
};
}, [link, thumbnailUrl, linkWidth, linkHeight, isInPostPageView, isInPendingPostView]);
const mediaInfo = getCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
// Return media info with cached thumbnail dimensions if available
if (thumbnailDimensions && mediaInfo) {
return {
...mediaInfo,
thumbnailWidth: thumbnailDimensions.width,
thumbnailHeight: thumbnailDimensions.height,
};
}
return mediaInfo;
return useMemo(() => {
const mediaInfo = getCommentMediaInfo(link, thumbnailUrl, linkWidth, linkHeight);
if (thumbnailDimensions && mediaInfo) {
return {
...mediaInfo,
thumbnailWidth: thumbnailDimensions.width,
thumbnailHeight: thumbnailDimensions.height,
};
}
return mediaInfo;
}, [link, thumbnailUrl, linkWidth, linkHeight, thumbnailDimensions]);
};
+9 -5
View File
@@ -11,6 +11,10 @@ interface GifFirstFrameState {
status: GifFirstFrameStatus;
}
const IDLE_STATE: GifFirstFrameState = { frameUrl: null, status: 'idle' };
const LOADING_STATE: GifFirstFrameState = { frameUrl: null, status: 'loading' };
const FAILED_STATE: GifFirstFrameState = { frameUrl: null, status: 'failed' };
const getCachedGifFrame = async (url: string): Promise<string | null> => {
return await gifFrameDb.getItem(url);
};
@@ -79,20 +83,20 @@ const parseGif = async (buf: ArrayBuffer): Promise<Blob> => {
};
const useFetchGifFirstFrame = (url: string | undefined) => {
const [gifFirstFrame, setGifFirstFrame] = useState<GifFirstFrameState>({ frameUrl: null, status: 'idle' });
const [gifFirstFrame, setGifFirstFrame] = useState<GifFirstFrameState>(IDLE_STATE);
useEffect(() => {
if (!url) {
setGifFirstFrame({ frameUrl: null, status: 'idle' });
setGifFirstFrame((prev) => (prev.status === 'idle' ? prev : IDLE_STATE));
return;
}
let isActive = true;
setGifFirstFrame({ frameUrl: null, status: 'loading' });
setGifFirstFrame((prev) => (prev.status === 'loading' ? prev : LOADING_STATE));
const fetchFrame = async () => {
if (failedUrls.has(url)) {
if (isActive) setGifFirstFrame({ frameUrl: null, status: 'failed' });
if (isActive) setGifFirstFrame((prev) => (prev.status === 'failed' ? prev : FAILED_STATE));
return;
}
@@ -119,7 +123,7 @@ const useFetchGifFirstFrame = (url: string | undefined) => {
} catch (error) {
failedUrls.add(url);
console.error('Failed to load GIF frame:', error);
if (isActive) setGifFirstFrame({ frameUrl: null, status: 'failed' });
if (isActive) setGifFirstFrame((prev) => (prev.status === 'failed' ? prev : FAILED_STATE));
}
};