useIntersection
Tracks the changes in the intersection of a target element with an ancestor element or with a top-level document's viewport. Uses the Intersection Observer API (opens in a new tab).
Usage
Here is an example of a <Thumbnail />
component that uses the useIntersection
to lazy load the image.
import { useState, useCallback } from 'react';
import { useIntersection } from 'foxact/use-intersection';
// A foxact hook that can be used to reset the state when the props changes
// see: https://foxact.skk.moe/use-component-will-receive-update
import { useComponentWillReceiveUpdate } from 'foxact/use-component-will-receive-update';
interface ThumbnailProps {
src: string;
isLazy?: boolean;
}
const Thumbnail = ({ src, isLazy }: ThumbnailProps) => {
const [setIntersection, isIntersected, resetIsIntersected] = useIntersection<HTMLImageElement>({
rootRef: null, // optional, the ref of the ancestor element
rootMargin: '200px', // optional
disabled: !isLazy // optional, allows to create reusable thumbnail component that supports both lazy and eager loading
});
// Reset the `isIntersected` state when the `src` prop changes
// You can find the docs about `useComponentWillReceiveUpdate` here: https://foxact.skk.moe/use-component-will-receive-update
useComponentWillReceiveUpdate(resetIsIntersected, [src])
return (
<img
// Use callback ref to tell the `useIntersection` hook which image element needs to be observed
// Wraps the callback ref with `useCallback` to avoid unnecessary invocations during re-render.
// See also react documentation about callback ref: https://react.dev/reference/react-dom/components/common#ref-callback
ref={useCallback((el: HTMLImageElement | null) => {
if (isLazy) {
setIntersection(el);
}
}, [isLazy, setIntersection])}
decoding="async"
alt={alt}
// https://stackoverflow.com/questions/6018611/smallest-data-uri-image-possible-for-a-transparent-image
src={isIntersected ? src : 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'}
/>
);
}