0

I am trying to use IntersectionObserver in my react app. I want to achieve lazy loading with it. Therefore I observe several elements and if they appear on screen I load content inside them.

Here is a very simplified code:

class Table extends React.Component {  
    constructor() {
    super()
    this.state = {
      entries: 0
    }
  }

  componentWillUnmount() {
    console.log('componentWillUnmount')
    if (this.observer) this.observer.disconnect()
  }


    observe (c) {
    if (!this.observer) {
      this.observer = new IntersectionObserver(
        entries => {
            this.setState({entries: entries.length})
        },
        { threshold: [0, 0.25, 0.5, 0.75, 1] }
      )
    }
    if (!c) return
    this.observer.observe(c)
  }

  render() {
    const {entries} = this.state
    return (
      <div>
        <h1>Number of observer entries: {entries}</h1>
        <div
          ref={this.observe.bind(this)}
          style={{height: '1000px', display: 'block', width: '500px'}}
        />
        <div
          ref={this.observe.bind(this)}
          style={{height: '1000px', display: 'block', width: '500px'}}
        />
      </div>
    )
  }
}

ReactDOM.render(<Table />, document.querySelector("#app"))

When a component is mounted it shows two elements are observed but as soon as I scroll down it changes to only one element. I have not idea what I am missing.

JSON fiddle - https://jsfiddle.net/w1zn49q6/12/

Joozty
  • 460
  • 2
  • 12
  • 40
  • The behaviour seems to be correct. Check slightly modified your fiddle. https://jsfiddle.net/mna41zv2/ – Viktor Yakubiv Dec 15 '19 at 18:51
  • I don't think so. What if I want to calculate visibility of several elements? Like I want to know which element is the most visible on screen. This is what intersection observer was built for, isn't it? If visibility changes I can check all observered elements and pick the most visible. I mean it's doable with storing multiple references or store parent reference but it makes the problem more complicated... – Joozty Dec 15 '19 at 19:06
  • To check visibility you may want to track only 2 points: 0 and 1. Intersection observer notifies you when an element passes through on of these points, i.e. you are able to know what element becomes visible and which one becomes invisible. – Viktor Yakubiv Dec 16 '19 at 10:18

1 Answers1

1

The divs are stacked one after the other vertically. In the initial render, as they are laid out, the intersection observer gets triggered for both, as they enter the viewport together (the first div enters, the second div exits). However, once they are rendered, they will enter/exit one at a time on a normal course of vertical scrolling, hence the entries will only ever contain one div, which intersected the x-axis most recently.

The intersection entry only reports a transition to/from 0 (not in view) from/to 1 (fully in view). So when one div has fully exited/entered the view, it will no longer be present in an entry update.

You can still get 2 entries however :). If you manage to scroll really fast! Try it using an accelerated mouse wheel. So basically, between two intersection calculations, if both the divs moved too far, both will raise the intersection event, but if they move slowly, the intersection will be gradual because they are stacked one by one.

If you would stack them in the same row, you will continuously get two entries, as both will be intersecting at the same moment with the x-axis.

hazardous
  • 10,627
  • 2
  • 40
  • 52