Skip to content

useInView

ts
useInView(target: Element, init?: IntersectionObserverInit): Service<InViewProps>

An IntersectionObserver as a service.

Props

ts
interface InViewProps {
  readonly isInView: boolean;
  readonly entry: IntersectionObserverEntry | null;
}

Usage

js
import { 
Base
,
useInView
} from '@studiometa/js-toolkit';
class
Reveal
extends
Base
{
static
config
= {
name
: 'Reveal' };
mounted
() {
return
useInView
(this.
$el
, {
threshold
: 0.25 }).
subscribe
(({
isInView
}) => {
this.
$el
.
classList
.
toggle
('is-in-view',
isInView
);
}); } }

Keying

useInView() keys every IntersectionObserverInit field, and gives an object root a stable weak identity so two callers passing the same root element share one service.

The options are read by meaning, not by spelling: keys are sorted at every depth and the ones holding undefined are dropped, so { threshold: 0.5, rootMargin: '0px' } and { rootMargin: '0px', threshold: 0.5 } are the same service.

Nothing groups observers across targets.

{ immediate: true } is the default here

withInView defaults it to true, because "am I in view" has a current answer and a consumer that has to wait for the first crossing to find out would be wrong on load.

This is not a mount strategy

useInView and withInView observe a component that is already mounted. They do not replace data-mount="visible" or data-mount="in-view", which decide whether the instance exists at all.

WantUse
the component to exist only once seendata-mount="visible"
the component to come and go with the viewportdata-mount="in-view"
a mounted component to react to crossingsuseInView() / withInView

See Mount strategies.

Mixin

js
class Reveal extends withInView(Base, { threshold: 0.25 }) {
  intersected({ isInView }) {}
}

MIT Licensed