Skip to content

Commit

Permalink
fix: ensure threshold fallbacks to options value if undefined (#416)
Browse files Browse the repository at this point in the history
  • Loading branch information
thebuilder authored Nov 12, 2020
1 parent 76405d7 commit 88780d1
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 4 deletions.
24 changes: 23 additions & 1 deletion src/__tests__/hooks.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useCallback } from 'react';
import { render } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import { useInView } from '../useInView';
import { intersectionMockInstance, mockAllIsIntersecting } from '../test-utils';
import { IntersectionOptions } from '../index';
Expand Down Expand Up @@ -257,3 +257,25 @@ test('should handle multiple hooks on the same element', () => {
expect(getByTestId('item-2').getAttribute('data-inview')).toBe('true');
expect(getByTestId('item-3').getAttribute('data-inview')).toBe('true');
});

test('should handle thresholds missing on observer instance', () => {
render(<HookComponent options={{ threshold: [0.1, 1] }} />);
const wrapper = screen.getByTestId('wrapper');
const instance = intersectionMockInstance(wrapper);
// @ts-ignore
instance.thresholds = undefined;
mockAllIsIntersecting(true);

screen.getByText('true');
});

test('should handle thresholds missing on observer instance with no threshold set', () => {
render(<HookComponent />);
const wrapper = screen.getByTestId('wrapper');
const instance = intersectionMockInstance(wrapper);
// @ts-ignore
instance.thresholds = undefined;
mockAllIsIntersecting(true);

screen.getByText('true');
});
12 changes: 9 additions & 3 deletions src/observers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,15 @@ function createObserver(options: IntersectionObserverInit) {
if (!instance) {
// 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.
const elements = new Map<Element, Array<ObserverInstanceCallback>>();
let thresholds: number[] | readonly number[];

const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
// 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.
// -Firefox ignores `threshold` when considering `isIntersecting`, so it will never be false again if `threshold` is > 0
const inView =
entry.isIntersecting &&
(observer.thresholds ?? [0]).some(
(threshold) => entry.intersectionRatio >= threshold,
);
thresholds.some((threshold) => entry.intersectionRatio >= threshold);

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

// Ensure we have a valid thresholds array. If not, use the threshold from the options
thresholds =
observer.thresholds ||
(Array.isArray(options.threshold)
? options.threshold
: [options.threshold || 0]);

instance = {
id,
observer,
Expand Down

1 comment on commit 88780d1

@vercel
Copy link

@vercel vercel bot commented on 88780d1 Nov 12, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.