UNPKG

react-intersection-observer

Version:

Monitor if a component is inside the viewport, using IntersectionObserver API

219 lines (202 loc) 9.11 kB
import * as React from 'react'; type State = { inView: boolean; entry?: IntersectionObserverEntry; }; /** ## Render props To use the `<InView>` component, you pass it a function. It will be called whenever the state changes, with the new value of `inView`. In addition to the `inView` prop, children also receive a `ref` that should be set on the containing DOM element. This is the element that the IntersectionObserver will monitor. If you need it, you can also access the [`IntersectionObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry) on `entry`, giving you access to all the details about the current intersection state. ```jsx import { InView } from 'react-intersection-observer'; const Component = () => ( <InView> {({ inView, ref, entry }) => ( <div ref={ref}> <h2>{`Header inside viewport ${inView}.`}</h2> </div> )} </InView> ); export default Component; ``` ## Plain children You can pass any element to the `<InView />`, and it will handle creating the wrapping DOM element. Add a handler to the `onChange` method, and control the state in your own component. Any extra props you add to `<InView>` will be passed to the HTML element, allowing you set the `className`, `style`, etc. ```jsx import { InView } from 'react-intersection-observer'; const Component = () => ( <InView as="div" onChange={(inView, entry) => console.log('Inview:', inView)}> <h2>Plain children are always rendered. Use onChange to monitor state.</h2> </InView> ); export default Component; ``` */ declare class InView extends React.Component<IntersectionObserverProps | PlainChildrenProps, State> { node: Element | null; _unobserveCb: (() => void) | null; lastInView: boolean | undefined; constructor(props: IntersectionObserverProps | PlainChildrenProps); componentDidMount(): void; componentDidUpdate(prevProps: IntersectionObserverProps): void; componentWillUnmount(): void; observeNode(): void; unobserve(): void; handleNode: (node?: Element | null) => void; handleChange: (inView: boolean, entry: IntersectionObserverEntry) => void; render(): React.ReactNode; } /** * What should be the default behavior if the IntersectionObserver is unsupported? * Ideally the polyfill has been loaded, you can have the following happen: * - `undefined`: Throw an error * - `true` or `false`: Set the `inView` value to this regardless of intersection state * **/ declare function defaultFallbackInView(inView: boolean | undefined): void; /** * @param element - DOM Element to observe * @param callback - Callback function to trigger when intersection status changes * @param options - Intersection Observer options * @param fallbackInView - Fallback inView value. * @return Function - Cleanup function that should be triggered to unregister the observer */ declare function observe(element: Element, callback: ObserverInstanceCallback, options?: IntersectionObserverInit, fallbackInView?: boolean | undefined): () => void; /** * React Hooks make it easy to monitor the `inView` state of your components. Call * the `useInView` hook with the (optional) [options](#options) you need. It will * return an array containing a `ref`, the `inView` status and the current * [`entry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry). * Assign the `ref` to the DOM element you want to monitor, and the hook will * report the status. * * @example * ```jsx * import React from 'react'; * import { useInView } from 'react-intersection-observer'; * * const Component = () => { * const { ref, inView, entry } = useInView({ * threshold: 0, * }); * * return ( * <div ref={ref}> * <h2>{`Header inside viewport ${inView}.`}</h2> * </div> * ); * }; * ``` */ declare function useInView({ threshold, delay, trackVisibility, rootMargin, root, triggerOnce, skip, initialInView, fallbackInView, onChange, }?: IntersectionOptions): InViewHookResponse; /** * React Hooks make it easy to monitor when elements come into and leave view. Call * the `useOnInView` hook with your callback and (optional) [options](#options). * It will return a ref callback that you can assign to the DOM element you want to monitor. * When the element enters or leaves the viewport, your callback will be triggered. * * This hook triggers no re-renders, and is useful for performance-critical use-cases or * when you need to trigger render independent side effects like tracking or logging. * * @example * ```jsx * import React from 'react'; * import { useOnInView } from 'react-intersection-observer'; * * const Component = () => { * const inViewRef = useOnInView((inView, entry) => { * if (inView) { * console.log("Element is in view", entry.target); * } else { * console.log("Element left view", entry.target); * } * }); * * return ( * <div ref={inViewRef}> * <h2>This element is being monitored</h2> * </div> * ); * }; * ``` */ declare const useOnInView: <TElement extends Element>(onIntersectionChange: IntersectionChangeEffect<TElement>, { threshold, root, rootMargin, trackVisibility, delay, triggerOnce, skip, }?: IntersectionEffectOptions) => (element: TElement | undefined | null) => (() => void) | undefined; type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; type ObserverInstanceCallback = (inView: boolean, entry: IntersectionObserverEntry) => void; type IntersectionChangeEffect<TElement extends Element = Element> = (inView: boolean, entry: IntersectionObserverEntry & { target: TElement; }) => void; interface RenderProps { inView: boolean; entry: IntersectionObserverEntry | undefined; ref: React.RefObject<any> | ((node?: Element | null) => void); } interface IntersectionOptions extends IntersectionObserverInit { /** The IntersectionObserver interface's read-only `root` property identifies the Element or Document whose bounds are treated as the bounding box of the viewport for the element which is the observer's target. If the `root` is null, then the bounds of the actual document viewport are used.*/ root?: Element | Document | null; /** Margin around the root. Can have values similar to the CSS margin property, e.g. `10px 20px 30px 40px` (top, right, bottom, left). */ rootMargin?: string; /** Number between `0` and `1` indicating the percentage that should be visible before triggering. Can also be an `array` of numbers, to create multiple trigger points. */ threshold?: number | number[]; /** Only trigger the inView callback once */ triggerOnce?: boolean; /** Skip assigning the observer to the `ref` */ skip?: boolean; /** Set the initial value of the `inView` boolean. This can be used if you expect the element to be in the viewport to start with, and you want to trigger something when it leaves. */ initialInView?: boolean; /** Fallback to this inView state if the IntersectionObserver is unsupported, and a polyfill wasn't loaded */ fallbackInView?: boolean; /** IntersectionObserver v2 - Track the actual visibility of the element */ trackVisibility?: boolean; /** IntersectionObserver v2 - Set a minimum delay between notifications */ delay?: number; /** Call this function whenever the in view state changes */ onChange?: (inView: boolean, entry: IntersectionObserverEntry) => void; } interface IntersectionObserverProps extends IntersectionOptions { /** * Children expects a function that receives an object * contain an `inView` boolean and `ref` that should be * assigned to the element root. */ children: (fields: RenderProps) => React.ReactNode; } /** * Types specific to the PlainChildren rendering of InView * */ type PlainChildrenProps = IntersectionOptions & { children?: React.ReactNode; /** * Render the wrapping element as this element. * This needs to be an intrinsic element. * If you want to use a custom element, please use the useInView * hook to manage the ref explicitly. * @default `'div'` */ as?: React.ElementType; /** Call this function whenever the in view state changes */ onChange?: (inView: boolean, entry: IntersectionObserverEntry) => void; } & Omit<React.HTMLProps<HTMLElement>, "onChange">; /** * The Hook response supports both array and object destructing */ type InViewHookResponse = [ (node?: Element | null) => void, boolean, IntersectionObserverEntry | undefined ] & { ref: (node?: Element | null) => void; inView: boolean; entry?: IntersectionObserverEntry; }; type IntersectionEffectOptions = Omit<IntersectionOptions, "onChange" | "fallbackInView" | "initialInView">; export { InView, type InViewHookResponse, type IntersectionChangeEffect, type IntersectionEffectOptions, type IntersectionObserverProps, type IntersectionOptions, type ObserverInstanceCallback, type PlainChildrenProps, defaultFallbackInView, observe, useInView, useOnInView };