Skip to content

Commit ac9d6b5

Browse files
feat(ui): optimize image loading and enhance layout handling
- Refactor grid column calculation to use useMemo for performance - Implement loading block during filter changes to prevent race conditions - Add layout transition detection to manage loading behavior
1 parent ab17d05 commit ac9d6b5

File tree

3 files changed

+46
-4
lines changed

3 files changed

+46
-4
lines changed

app/src/components/ImageCard.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ export const ImageCard = memo(function ImageCard({
6060
}: ImageCardProps) {
6161
const theme = useTheme();
6262
const isXs = useMediaQuery(theme.breakpoints.down('sm')); // < 600px
63-
const isSm = useMediaQuery(theme.breakpoints.between('sm', 'md')); // 600-900px
6463

6564
const labelFontSize = imageSize === 'compact' ? '0.65rem' : '0.8rem';
6665
const labelLetterSpacing = isXs ? '-0.03em' : 'normal';

app/src/components/ImagesGrid.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,12 @@ export function ImagesGrid({
5050
void _onImageLoad; // Removed for performance - was causing re-renders per image load
5151

5252
// Grid columns: normal = max 3 cols, compact = max 6 cols
53-
const gridColumns = imageSize === 'compact'
54-
? { xs: 6, sm: 6, md: 3, lg: 3, xl: 2 } // 2→2→4→4→6 cols
55-
: { xs: 12, sm: 12, md: 6, lg: 6, xl: 4 }; // 1→1→2→2→3 cols
53+
const gridColumns = useMemo(() =>
54+
imageSize === 'compact'
55+
? { xs: 6, sm: 6, md: 3, lg: 3, xl: 2 } // 2→2→4→4→6 cols
56+
: { xs: 12, sm: 12, md: 6, lg: 6, xl: 4 }, // 1→1→2→2→3 cols
57+
[imageSize]
58+
);
5659

5760
// Create O(1) lookup Maps from arrays
5861
const libraryMap = useMemo(() => {

app/src/hooks/useInfiniteScroll.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,31 @@ export function useInfiniteScroll({
2323
const stateRef = useRef({ allImages, displayedImages, hasMore });
2424
stateRef.current = { allImages, displayedImages, hasMore };
2525

26+
// Track document height to detect layout transitions
27+
const lastDocHeightRef = useRef(0);
28+
const layoutTransitionRef = useRef(false);
29+
const loadBlockedRef = useRef(false);
30+
31+
// Block loading and reset tracking when data changes (new filter results)
32+
useEffect(() => {
33+
// Block loading to prevent race conditions during filter change
34+
loadBlockedRef.current = true;
35+
lastDocHeightRef.current = 0;
36+
layoutTransitionRef.current = false;
37+
38+
// Unblock after state has settled
39+
const timer = setTimeout(() => {
40+
loadBlockedRef.current = false;
41+
}, 150);
42+
43+
return () => clearTimeout(timer);
44+
}, [allImages]);
45+
2646
// Load more images
2747
const loadMore = useCallback(() => {
48+
// Skip if loading is blocked (filter change in progress)
49+
if (loadBlockedRef.current) return;
50+
2851
const { allImages: all, displayedImages: displayed, hasMore: more } = stateRef.current;
2952
if (!more) return;
3053

@@ -41,12 +64,29 @@ export function useInfiniteScroll({
4164

4265
// Check if we need to load more based on scroll position
4366
const checkAndLoad = useCallback(() => {
67+
// Skip if loading is blocked (filter change in progress)
68+
if (loadBlockedRef.current) return;
69+
4470
const { hasMore: more } = stateRef.current;
4571
if (!more) return;
4672

4773
const scrollBottom = window.scrollY + window.innerHeight;
4874
const docHeight = document.documentElement.scrollHeight;
4975

76+
// Detect layout transitions (significant height changes)
77+
const heightDiff = Math.abs(docHeight - lastDocHeightRef.current);
78+
if (heightDiff > 500 && lastDocHeightRef.current > 0) {
79+
// Layout is transitioning (e.g., compact/normal switch), pause loading
80+
layoutTransitionRef.current = true;
81+
setTimeout(() => {
82+
layoutTransitionRef.current = false;
83+
}, 300);
84+
}
85+
lastDocHeightRef.current = docHeight;
86+
87+
// Skip loading during layout transitions
88+
if (layoutTransitionRef.current) return;
89+
5090
// If within 2500px of bottom, load more
5191
if (scrollBottom + 2500 > docHeight) {
5292
loadMore();

0 commit comments

Comments
 (0)