diff --git a/src/__tests__/useInView.test.tsx b/src/__tests__/useInView.test.tsx index cc664e86..aa47c4a9 100644 --- a/src/__tests__/useInView.test.tsx +++ b/src/__tests__/useInView.test.tsx @@ -1,4 +1,4 @@ -import { render, screen } from "@testing-library/react"; +import { act, render, screen } from "@testing-library/react"; import React, { useCallback } from "react"; import { defaultFallbackInView, type IntersectionOptions } from "../index"; import { @@ -118,6 +118,38 @@ test("should respect trigger once", () => { getByText("true"); }); +test("should respect the threshold before triggering once", () => { + const { getByTestId, getByText } = render( + , + ); + const wrapper = getByTestId("wrapper"); + const instance = intersectionMockInstance(wrapper); + const callback = vi.mocked(window.IntersectionObserver).mock.calls[0][0]; + const createEntry = ( + intersectionRatio: number, + ): IntersectionObserverEntry => ({ + boundingClientRect: wrapper.getBoundingClientRect(), + intersectionRatio, + intersectionRect: wrapper.getBoundingClientRect(), + isIntersecting: true, + rootBounds: null, + target: wrapper, + time: performance.now(), + }); + + act(() => callback([createEntry(0.25)], instance)); + + getByText("false"); + expect(instance.unobserve).not.toHaveBeenCalled(); + + act(() => callback([createEntry(0.5)], instance)); + + getByText("true"); + expect(instance.unobserve).toHaveBeenCalledTimes(1); +}); + test("should trigger onChange", () => { const onChange = vi.fn(); render(); diff --git a/src/useInView.tsx b/src/useInView.tsx index 791c5014..c39871e1 100644 --- a/src/useInView.tsx +++ b/src/useInView.tsx @@ -85,7 +85,7 @@ export function useInView({ }); if (callback.current) callback.current(inView, entry); - if (entry.isIntersecting && triggerOnce && unobserve) { + if (inView && triggerOnce && unobserve) { // If it should only trigger once, unobserve the element after it's inView unobserve(); unobserve = undefined;