Skip to content

alisaitbilgi/react-dev-comps.intersection-observer

Repository files navigation

Observe changes in the intersection of a target element.

React component to observe changes in the intersection of a target element or within the document's viewport by using Intersection Observer API.

Intersection information for a react component is needed for many reasons and can be used as:

Installation

npm install react-dev-comps.intersection-observer --save

Usage

  • Using as infinite-scroller:

Place it as the latest item in list and execute fetch handler on your onEnter callback.

import InfiniteScroller from 'react-dev-comps.intersection-observer';

<div className="list-container">
    <div className="each-todo-item" />
    <div className="each-todo-item" />
    <div className="each-todo-item" />

    { /*... any other items ...*/ }

    <InfiniteScroller onEnter={this.fetchNextList}/>
</div>

demo-1

  • Using as lazy-loader:

Place it as the latest item in list and execute image handler on your onEnter callback.

import LazyLoad from 'react-dev-comps.intersection-observer';

// Since we have 3 images on each row, not to broke style, we used targetStyle prop.

<div className="image-container">
    <img className="each-image" src="" />
    <img className="each-image" src="" />
    <img className="each-image" src="" />

    { /*... any other images ...*/ }

    <LazyLoad
        targetStyle={{ width: "100%", height: "0" }}
        onEnter={this.getNextImages}
    />
</div>

demo-1

  • Using as inview-controller:

Lets say we have an image and zoom-control buttons to zoom in/out. When zoomed in/out, image may be lost from viewport. (as an implementation side-effect)

<div className="app">
    <ImageContainer />
    <ZoomController />
</div>

demo-1

To overcome this issue, wrap the image with InViewController component and reset the image position on your onLeave callback.

import InViewController from 'react-dev-comps.intersection-observer';

<div className="app">
    <InViewController onLeave={this.resetImagePosition}>
        <ImageContainer />
    </InViewController>
    <ZoomController />
</div>

demo-1

  • Using as task-performer:

Wrap the video container with InViewController component and perform your tasks/animations on your onEnter and onLeave callbacks.

import InViewController from 'react-dev-comps.intersection-observer';

<div className="app">
    <InViewController
        onEnter={this.playVideo}
        onLeave={this.pauseVideo}
    >
        <VideoContainer />
    </InViewController>
</div>

demo-1

  • Using as ads-visibility-timer:

Wrap the AdvertisementPanel with InViewController component and start/stop your timers on your callbacks.

import InViewController from 'react-dev-comps.intersection-observer';

<div className="app">
    <InViewController
        onEnter={this.startTimer}
        onLeave={this.stopTimer}
    >
        <AdvertisementPanel />
    </InViewController>
</div>

demo-1

API

react-dev-comps.intersection-observer exposes a React Component which takes the following props:

  • onIntersect: A cb, invoked when target element intersects with the root. (either intersecting in or out)
  • onEnter: A cb, invoked when target element is visible within the root element. (or viewport)
  • onLeave: A cb, invoked when target element has lost visibility within the root element. (or viewport)
  • onUpdate: An array of variables which must be described when any of your callbacks are using any kind of data. Variables must be the datas you are using on your callbacks. Example
  • options: An object passed to IntersectionObserver() constructor to let you control the circumstances for invocation of observer's callbacks. Defaults to {root: null, rootMargin: '0', threshold: 1}
  • targetClass: A string class name for target element. Defaults to "intersection-target"
  • targetStyle: An object for inner styling target element. Defaults to empty object
  • children: A react children component which will be the child of the intersection target element. Defaults to null

Callbacks will be invoked with 2 arguments.

Extra Use Cases

  1. Let's say, you're depending on some data (variables, props, state-variables etc.) on any of your callbacks. For that situation, you must provide those variables as onUpdate elements to use those variables' latest/updated versions on your callbacks. If you don't use onUpdate prop as required, your callbacks will always be executed with the initial values of those variables.

    import InfiniteScroller from 'react-dev-comps.intersection-observer';
    
    <div className="list-container">
        <div className="each-todo-item" />
        <div className="each-todo-item" />
        <div className="each-todo-item" />
    
        { /*... any other items ...*/ }
    
        // We need fresh versions of *anyPropVariable* and *anyStateVariable* datas.
        <InfiniteScroller
            onEnter={() => {
                if (this.props.anyPropVariable) {
                    // do someting...
                }
    
                if (this.state.anyStateVariable) {
                    // do someting...
                }
            }}
    
            // We **must** provide those variables on our onUpdate array prop.
            onUpdate={[ this.props.anyPropVariable, this.state.anyStateVariable ]}
        />
    </div>
  2. Let's say, you have to execute some essential tasks (fetching new items and append to the list) and some background tasks which are non-essential to be completed priorly. For that situation, react-dev-comps.intersection-observer also exposes background-tasks-api with the method name scheduleTasksOnBackground. Although it is a standalone package on npm, you can import and use it as:

    import InfiniteScroller, { scheduleTasksOnBackground } from 'react-dev-comps.intersection-observer';
    
    var nonEssentialWork1 = () => { /* do something */ };
    var nonEssentialWork2 = () => { /* do something */ };
    var tasks = [ nonEssentialWork1, nonEssentialWork2 ];
    
    <div className="list-container">
        <div className="each-todo-item" />
        <div className="each-todo-item" />
        <div className="each-todo-item" />
    
        { /*... any other items ...*/ }
    
        <InfiniteScroller
            onEnter={() => {
                scheduleTasksOnBackground(tasks); // non-essential tasks will be executed on idle callbacks.
                this.fetchNextList(); // free to execute prior tasks on main thread.
            }}
        />
    </div>

License

Licensed under the MIT License, Copyright © 2019-present.

See LICENSE for more information.

About

Observe changes in the intersection of a target element.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published