perf: optimized gradientblinds

This commit is contained in:
Melvin Ragusa
2026-01-24 11:33:46 +01:00
parent e6df2d25be
commit 6b17b8b007
2 changed files with 55 additions and 12 deletions

View File

@@ -28,6 +28,7 @@ vi.mock('ogl', () => {
Triangle: class { Triangle: class {
remove() { } remove() { }
}, },
}; };
}); });
@@ -41,6 +42,8 @@ globalThis.ResizeObserver = class ResizeObserver {
describe('GradientBlinds', () => { describe('GradientBlinds', () => {
let rafSpy: any; let rafSpy: any;
let cancelRafSpy: any; let cancelRafSpy: any;
let addEventListenerSpy: any;
let removeEventListenerSpy: any;
let ioCallback: (entries: IntersectionObserverEntry[]) => void; let ioCallback: (entries: IntersectionObserverEntry[]) => void;
let observeSpy: any; let observeSpy: any;
let disconnectSpy: any; let disconnectSpy: any;
@@ -51,6 +54,8 @@ describe('GradientBlinds', () => {
}); });
cancelRafSpy = vi.spyOn(window, 'cancelAnimationFrame').mockImplementation((_id: number) => { cancelRafSpy = vi.spyOn(window, 'cancelAnimationFrame').mockImplementation((_id: number) => {
}); });
addEventListenerSpy = vi.spyOn(window, 'addEventListener');
removeEventListenerSpy = vi.spyOn(window, 'removeEventListener');
// Mock IntersectionObserver // Mock IntersectionObserver
observeSpy = vi.fn(); observeSpy = vi.fn();
@@ -133,6 +138,44 @@ describe('GradientBlinds', () => {
expect(disconnectSpy).toHaveBeenCalled(); expect(disconnectSpy).toHaveBeenCalled();
}); });
it('toggles pointer event listener based on visibility', () => {
const { unmount } = render(<GradientBlinds />);
// Should not listen initially (not visible)
// Initially not called
expect(addEventListenerSpy).not.toHaveBeenCalledWith('pointermove', expect.any(Function));
// Simulate on-screen
act(() => {
if (ioCallback) {
ioCallback([{ isIntersecting: true } as IntersectionObserverEntry]);
}
});
expect(addEventListenerSpy).toHaveBeenCalledWith('pointermove', expect.any(Function));
// Reset
addEventListenerSpy.mockClear();
removeEventListenerSpy.mockClear();
// Simulate off-screen
act(() => {
if (ioCallback) {
ioCallback([{ isIntersecting: false } as IntersectionObserverEntry]);
}
});
expect(removeEventListenerSpy).toHaveBeenCalledWith('pointermove', expect.any(Function));
// Simulate on-screen again
act(() => {
if (ioCallback) {
ioCallback([{ isIntersecting: true } as IntersectionObserverEntry]);
}
});
expect(addEventListenerSpy).toHaveBeenCalledWith('pointermove', expect.any(Function));
unmount();
expect(removeEventListenerSpy).toHaveBeenCalledWith('pointermove', expect.any(Function));
});
it('minimizes getBoundingClientRect calls during pointer move', () => { it('minimizes getBoundingClientRect calls during pointer move', () => {
const { unmount } = render(<GradientBlinds />); const { unmount } = render(<GradientBlinds />);
@@ -155,8 +198,7 @@ describe('GradientBlinds', () => {
window.dispatchEvent(event); window.dispatchEvent(event);
}); });
// EXPECTATION: It should NOT be called. // EXPECTATION: It should NOT be called because the listener shouldn't be attached (not visible)
// This will fail currently.
expect(spy).not.toHaveBeenCalled(); expect(spy).not.toHaveBeenCalled();
unmount(); unmount();

View File

@@ -330,7 +330,6 @@ void main() {
uniforms.iMouse.value = [x, y]; uniforms.iMouse.value = [x, y];
} }
}; };
window.addEventListener('pointermove', onPointerMove);
const loop = (t: number) => { const loop = (t: number) => {
rafRef.current = requestAnimationFrame(loop); rafRef.current = requestAnimationFrame(loop);
@@ -364,11 +363,13 @@ void main() {
lastTimeRef.current = 0; lastTimeRef.current = 0;
rafRef.current = requestAnimationFrame(loop); rafRef.current = requestAnimationFrame(loop);
} }
window.addEventListener('pointermove', onPointerMove);
} else { } else {
if (rafRef.current) { if (rafRef.current) {
cancelAnimationFrame(rafRef.current); cancelAnimationFrame(rafRef.current);
rafRef.current = null; rafRef.current = null;
} }
window.removeEventListener('pointermove', onPointerMove);
} }
}); });
observer.observe(container); observer.observe(container);