react-intersection-observer

React component for the Intersection API

Github stars Tracking Chart

Bring ReactIntersectionObserver over today, your React children will love it!

React Intersection Observer is a React component, acting as a wrapper
for the IntersectionObserver API. It is fully declarative and takes care of
all the imperative parts for you.

React Intersection Observer is good at:

  • reusing instances: comparing the passed options
  • performance: chooses smartly when to re-render and when to re-observe
  • being unopinionated: how to handle visibility changes is left entirely up
    to the developer
  • being intuitive: looks like the Native API

Getting started

npm install --save @researchgate/react-intersection-observer

Usage:

import React from 'react';
import 'intersection-observer'; // optional polyfill
import Observer from '@researchgate/react-intersection-observer';

class ExampleComponent extends React.Component {
  handleIntersection(event) {
    console.log(event.isIntersecting);
  }

  render() {
    const options = {
      onChange: this.handleIntersection,
      root: '#scrolling-container',
      rootMargin: '0% 0% -25%',
    };

    return (
      <div id="scrolling-container" style={{ overflow: 'scroll', height: 100 }}>
        <Observer {...options}>
          <div>I am the target element</div>
        </Observer>
      </div>
    );
  }
}

Optionally add the polyfill and make sure it's required on your
dependendencies for unsupporting browsers:

npm install --save intersection-observer

What does IntersectionObserver do?

IntersectionObservers calculate how much of a target element overlaps (or
"intersects with") the visible portion of a page, also known as the browser's
"viewport":

Dan Callahan · 

Graphic example

Why use this component?

The motivation is to provide the easiest possible solution for observing
elements that enter the viewport on your React codebase. It's fully
declarative and all complexity is abstracted away, focusing on reusability, and
low memory consumption.

No bookkeeping

It's built with compatibility in mind, adhering 100% to the
native API
implementation and DSL, but takes care of all the bookkeeping work for you.

Instances and nodes are managed internally so that any changes to the passed
options or tree root reconciliation cleans up and re-observes nodes on-demand to
avoid any unexpected memory leaks.

No extra markup

ReactIntersectionObserver does not create any extra DOM elements, it attaches to
the only child you'll provide to it. This is done using findDOMNode to
retrieve the first DOM node found. If your child already has an existing ref,
either a callback or object (from createRef), these will be handled normally in
either case.

Easy to adopt

When using ReactIntersectionObserver the only required prop is the onChange
function. Any changes to the visibility of the element will invoke this
callback, just like in the
native API -
you’ll receive one IntersectionObserverEntry argument per change. This gives
you an ideal and flexible base to build upon.

Some of the things you may want to use ReactIntersectionObserver for:

Documentation

Demos

Find multiple examples and usage guidelines under:
https://researchgate.github.io/react-intersection-observer/

demo

Recipes

Recipes are useful code snippets solutions to common problems, for example, how
to use ReactIntersectionObserver within a
Higher Order Component.
Here's how to create an element monitoring component:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Observer from '@researchgate/react-intersection-observer';

export default class ViewableMonitor extends Component {
  static propTypes = {
    tag: PropTypes.node,
    children: PropTypes.func.isRequired,
  };

  static defaultProps = {
    tag: 'div',
  };

  state = {
    isIntersecting: false,
  };

  handleChange = ({ isIntersecting }) => {
    this.setState({ isIntersecting });
  };

  render() {
    const { tag: Tag, children, ...rest } = this.props;

    return (
      <Observer {...rest} onChange={this.handleChange}>
        <Tag>{children(this.state.isIntersecting)}</Tag>
      </Observer>
    );
  }
}
import React from 'react';
import ViewableMonitor from './ViewableMonitor';

export default () => (
  <ViewableMonitor>
    {isViewable => (isViewable ? 'I am viewable' : 'I am still hiding')}
  </ViewableMonitor>
);

Discover more recipes in our examples section.

Exception handling

By default, an invariant error is thrown if there isn't a DOM node to observe
when mounted. We've added a helpful and descriptive message that's supposed to
help you identify potential problems early on. However, this could also
unexpectedtly trigger in production, specially with dynamic children, causing a
bigger problem (bubbling up) if not handled correctly (e.g.: error boundary). In
such cases, you can set the config for the error reporter to adjust it to your
needs:

import { Config } from '@researchgate/react-intersection-observer';

Config.errorReporter(function(errorMsg) {
    if (process.env.NODE_ENV === 'production') {
        sendReport((errorMsg);
    } else {
        console.error(errorMsg);
    }
});

Options

root: HTMLElement, string, default window object

The element or selector string that is used as the viewport for checking
visibility of the target.

rootMargin: string, default 0px 0px 0px 0px

Margin around the root. Specify using units px or % (top, right, bottom
left). Can contain negative values.

threshold: number, Array<number>, default: 0

Indicates at what percentage of the target's visibility the observer's callback
should be executed. If you only want to detect when visibility passes the 50%
mark, you can use a value of 0.5. If you want the callback run every time
visibility passes another 25%, you would specify the array [0, 0.25, 0.5, 0.75,
1].

disabled: boolean, default: false

Controls whether the element should stop being observed by its
IntersectionObserver instance. Useful for temporarily disabling the observing
mechanism and restoring it later.

onChange (required):
(entry: IntersectionObserverEntry, unobserve: () => void) => void

Function that will be invoked whenever an observer's callback contains this
target in its changes.

children: React.Element<*>, null

Single React component or element that is used as the target (observable). As of
v1.0.0, children can be null. Null children won't be observed.

Notes

  • According to the spec, an initial event is being fired when starting to
    observe a non-intersecting element as well.
  • Changes happen asynchronously, similar to the way requestIdleCallback works.
  • Although you can consider callbacks immediate - always below 1 second - you
    can also get an immediate response on an element's visibility with
    observer.takeRecords().
  • The primitives Map an Set are required. You may need to include a polyfill
    for browsers lacking ES2015 support. If you're using babel, include
    "babel-polyfill" somewhere to your codebase.

Polyfill

When needing the full spec's support, we highly recommend using the
IntersectionObserver polyfill.

Caveats

Ealier Spec

Earlier preview versions of
Edge
and prior to version 58 of
Chrome, the
support for isIntersecting was lacking. This property was added to the spec
later and both teams where unable to implement it earlier.

Performance issues

As the above-mentioned polyfill doesn't perform callback invocation
asynchronously, you
might want to decorate your onChange callback with a requestIdleCallback or
setTimeout call to avoid a potential performance degradation:

onChange = entry => requestIdleCallback(() => this.handleChange(entry));

IntersectionObserver's Browser Support

Out of the box

  • [1]reportedly available,
    it didn't trigger the events on initial load and lacks isIntersecting until
    later versions.
  • [2] This feature was implemented in Gecko 53.0 (Firefox 53.0 / Thunderbird
    53.0 / SeaMonkey 2.50) behind the preference
    dom.IntersectionObserver.enabled.

Using polyfill

Contributing

We'd love your help on creating React Intersection Observer!

Before you do, please read our Code of Conduct so
you know what we expect when you contribute to our projects.

Our Contributing Guide tells you about our
development process and what we're looking for, gives you instructions on how to
issue bugs and suggest features, and explains how you can build and test your
changes.

Haven't contributed to an open source project before? No problem!
Contributing Guide has you covered as well.

Main metrics

Overview
Name With Ownerresearchgate/react-intersection-observer
Primary LanguageJavaScript
Program languageJavaScript (Language Count: 3)
Platform
License:MIT License
所有者活动
Created At2017-08-01 21:20:23
Pushed At2023-07-19 05:26:06
Last Commit At2023-02-21 10:29:33
Release Count34
Last Release Namev1.3.5 (Posted on )
First Release Namev0.1.0 (Posted on )
用户参与
Stargazers Count1.1k
Watchers Count13
Fork Count60
Commits Count487
Has Issues Enabled
Issues Count49
Issue Open Count3
Pull Requests Count229
Pull Requests Open Count17
Pull Requests Close Count65
项目设置
Has Wiki Enabled
Is Archived
Is Fork
Is Locked
Is Mirror
Is Private