Performance: Disable animations when there are a large number of tiles

I don't believe this affects the cost of running the useSprings hook, but it at least skips the animation frames that would otherwise follow, so it's worth a try.
This commit is contained in:
Robin
2026-08-05 11:38:33 +02:00
parent eb65a28a75
commit dd59519a85

View File

@@ -41,6 +41,8 @@ import { TileWrapper } from "./TileWrapper";
import { usePrefersReducedMotion } from "../usePrefersReducedMotion"; import { usePrefersReducedMotion } from "../usePrefersReducedMotion";
import { useInitial } from "../useInitial"; import { useInitial } from "../useInitial";
const MAX_ANIMATED_TILES = 50; // Capped for performance reasons
interface Rect { interface Rect {
x: number; x: number;
y: number; y: number;
@@ -285,7 +287,6 @@ export function Grid<
const [visibleTilesCallback, setVisibleTilesCallback] = const [visibleTilesCallback, setVisibleTilesCallback] =
useState<VisibleTilesCallback | null>(null); useState<VisibleTilesCallback | null>(null);
const tiles = useInitial(() => new Map<string, Tile<TileModel>>()); const tiles = useInitial(() => new Map<string, Tile<TileModel>>());
const prefersReducedMotion = usePrefersReducedMotion();
const Slot: FC<SlotProps<TileModel>> = useMemo( const Slot: FC<SlotProps<TileModel>> = useMemo(
() => () =>
@@ -372,6 +373,10 @@ export function Grid<
// react-spring's imperative API during gestures to improve responsiveness // react-spring's imperative API during gestures to improve responsiveness
const dragState = useRef<DragState | null>(null); const dragState = useRef<DragState | null>(null);
// If true, disables animations
const immediate =
usePrefersReducedMotion() || placedTiles.length > MAX_ANIMATED_TILES;
const [tileTransitions, springRef] = useTransition( const [tileTransitions, springRef] = useTransition(
placedTiles, placedTiles,
() => ({ () => ({
@@ -389,9 +394,9 @@ export function Grid<
y, y,
width, width,
height, height,
immediate: prefersReducedMotion, immediate,
}), }),
enter: { opacity: 1, scale: 1, immediate: prefersReducedMotion }, enter: { opacity: 1, scale: 1, immediate },
update: ({ update: ({
id, id,
x, x,
@@ -406,9 +411,9 @@ export function Grid<
y, y,
width, width,
height, height,
immediate: prefersReducedMotion, immediate,
}, },
leave: { opacity: 0, scale: 0, immediate: prefersReducedMotion }, leave: { opacity: 0, scale: 0, immediate },
config: { mass: 0.7, tension: 252, friction: 25 }, config: { mass: 0.7, tension: 252, friction: 25 },
}), }),
// react-spring's types are bugged and can't infer the spring type // react-spring's types are bugged and can't infer the spring type
@@ -441,8 +446,7 @@ export function Grid<
y: tile.y, y: tile.y,
width: tile.width, width: tile.width,
height: tile.height, height: tile.height,
immediate: immediate: immediate || ((key): boolean => key === "zIndex"),
prefersReducedMotion || ((key): boolean => key === "zIndex"),
// Allow the tile's position to settle before pushing its // Allow the tile's position to settle before pushing its
// z-index back down // z-index back down
delay: (key): number => (key === "zIndex" ? 500 : 0), delay: (key): number => (key === "zIndex" ? 500 : 0),
@@ -453,7 +457,7 @@ export function Grid<
x: tileX, x: tileX,
y: tileY, y: tileY,
immediate: immediate:
prefersReducedMotion || immediate ||
((key): boolean => ((key): boolean =>
key === "zIndex" || key === "x" || key === "y"), key === "zIndex" || key === "x" || key === "y"),
}, },