Skip to content

Commit 88780d1

Browse files
authored
fix: ensure threshold fallbacks to options value if undefined (#416)
1 parent 76405d7 commit 88780d1

File tree

2 files changed

+32
-4
lines changed

2 files changed

+32
-4
lines changed

src/__tests__/hooks.test.tsx

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useCallback } from 'react';
2-
import { render } from '@testing-library/react';
2+
import { render, screen } from '@testing-library/react';
33
import { useInView } from '../useInView';
44
import { intersectionMockInstance, mockAllIsIntersecting } from '../test-utils';
55
import { IntersectionOptions } from '../index';
@@ -257,3 +257,25 @@ test('should handle multiple hooks on the same element', () => {
257257
expect(getByTestId('item-2').getAttribute('data-inview')).toBe('true');
258258
expect(getByTestId('item-3').getAttribute('data-inview')).toBe('true');
259259
});
260+
261+
test('should handle thresholds missing on observer instance', () => {
262+
render(<HookComponent options={{ threshold: [0.1, 1] }} />);
263+
const wrapper = screen.getByTestId('wrapper');
264+
const instance = intersectionMockInstance(wrapper);
265+
// @ts-ignore
266+
instance.thresholds = undefined;
267+
mockAllIsIntersecting(true);
268+
269+
screen.getByText('true');
270+
});
271+
272+
test('should handle thresholds missing on observer instance with no threshold set', () => {
273+
render(<HookComponent />);
274+
const wrapper = screen.getByTestId('wrapper');
275+
const instance = intersectionMockInstance(wrapper);
276+
// @ts-ignore
277+
instance.thresholds = undefined;
278+
mockAllIsIntersecting(true);
279+
280+
screen.getByText('true');
281+
});

src/observers.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,15 @@ function createObserver(options: IntersectionObserverInit) {
5050
if (!instance) {
5151
// Create a map of elements this observer is going to observe. Each element has a list of callbacks that should be triggered, once it comes into view.
5252
const elements = new Map<Element, Array<ObserverInstanceCallback>>();
53+
let thresholds: number[] | readonly number[];
5354

5455
const observer = new IntersectionObserver((entries) => {
5556
entries.forEach((entry) => {
5657
// While it would be nice if you could just look at isIntersecting to determine if the component is inside the viewport, browsers can't agree on how to use it.
5758
// -Firefox ignores `threshold` when considering `isIntersecting`, so it will never be false again if `threshold` is > 0
5859
const inView =
5960
entry.isIntersecting &&
60-
(observer.thresholds ?? [0]).some(
61-
(threshold) => entry.intersectionRatio >= threshold,
62-
);
61+
thresholds.some((threshold) => entry.intersectionRatio >= threshold);
6362

6463
// @ts-ignore support IntersectionObserver v2
6564
if (options.trackVisibility && typeof entry.isVisible === 'undefined') {
@@ -74,6 +73,13 @@ function createObserver(options: IntersectionObserverInit) {
7473
});
7574
}, options);
7675

76+
// Ensure we have a valid thresholds array. If not, use the threshold from the options
77+
thresholds =
78+
observer.thresholds ||
79+
(Array.isArray(options.threshold)
80+
? options.threshold
81+
: [options.threshold || 0]);
82+
7783
instance = {
7884
id,
7985
observer,

0 commit comments

Comments
 (0)