Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[useIntersectionObserver] Introduce new API #16663

Closed
2 tasks done
pranshuchittora opened this issue Jul 20, 2019 · 7 comments
Closed
2 tasks done

[useIntersectionObserver] Introduce new API #16663

pranshuchittora opened this issue Jul 20, 2019 · 7 comments
Labels
new feature New feature or request waiting for 👍 Waiting for upvotes

Comments

@pranshuchittora
Copy link
Contributor

pranshuchittora commented Jul 20, 2019

Note: This proposal is in its very early stage.

The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport.

  • This is not a v0.x issue.
  • I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior 🤔

Implementation should somewhat look like useScrollTrigger

Current Behavior 😯

User implemented

Examples 🌈

Context 🔦

  • Mount component when it intersects with the DOM.

Benchmark

@oliviertassinari
Copy link
Member

oliviertassinari commented Jul 21, 2019

@pranshuchittora Could you develop why Material-UI should solve this problem? Would it be better handled in a generic hook library? For instance https://github.com/thebuilder/react-intersection-observer?


In the past, I have used this implementation (before hooks were available):

import React from 'react'
import PropTypes from 'prop-types'
import waitUntil from 'modules/async/waitUntil'

class IntersectionObserver extends React.Component {
  state = {
    visible: this.props.defaultVisible,
  }

  async componentDidMount() {
    if (this.props.defaultVisible) {
      return
    }

    await waitUntil(() => ({ predicate: Boolean(window.IntersectionObserver) }), {
      delay: 300,
      tries: 10,
    })

    this.io = new window.IntersectionObserver(entries => {
      const entry = entries[0]
      if (this.state.visible !== entry.isIntersecting && entry.isIntersecting === true) {
        this.setState({ visible: entry.isIntersecting })
        this.io.disconnect()
      }
    }, this.props.options)
    this.io.observe(this.container)
  }

  componentWillUnmount() {
    if (this.io) {
      this.io.disconnect()
    }
  }

  handleRef = ref => {
    this.container = ref
  }

  render() {
    const { children, defaultVisible, options, ...other } = this.props

    return (
      <div ref={this.handleRef} {...other}>
        {children({ visible: this.state.visible })}
      </div>
    )
  }
}

IntersectionObserver.propTypes = {
  children: PropTypes.func.isRequired,
  defaultVisible: PropTypes.bool,
  options: PropTypes.object,
}

IntersectionObserver.defaultProps = {
  defaultVisible: false,
}

IntersectionObserver.displayName = 'IntersectionObserver'

export default IntersectionObserver

Usage:

          <IntersectionObserver
            defaultVisible={listIndex < 25}
            options={{
              rootMargin: '0px 0px 400px 0px',
            }}
          >
            {({ visible }) => (
              <img
                alt={getAlt(image)}
                height={height}
                width={width}
                className={classes.img}
                src={visible ? image.url.small : searchEmpty}
                data-e2e="gallery.image.imgTag"
              />
            )}
          </IntersectionObserver>

Polyfill for Safari and IE:

          <script
            defer
            src="https://polyfill.io/v3/polyfill.min.js?flags=gated&features=IntersectionObserver&unknown=polyfill"
          />

@oliviertassinari
Copy link
Member

I have added the waiting for users upvotes tag. I'm closing the issue as we are not sure people are looking for such abstraction. So please upvote this issue if you are. We will prioritize our effort based on the number of upvotes.

@pranshuchittora
Copy link
Contributor Author

Sorry for the late reply. I know that this can be implemented using a third-party package, but this requires a lot of boilerplate code. Apart from that, there might be some performance issue(maybe).

If there's a native implementation in the MUI. Then it opens a room for an awesome fast components like.

  • Infinite scroller
  • onIntersect component rendering (decongests the DOM tree)
  • Lazy Image fetching

@oliviertassinari
Copy link
Member

To further expand on my reasoning.we can compare the usage rate between the generic API https://github.com/thebuilder/react-intersection-observer and the specialized one: https://github.com/jasonslyvia/react-lazyload, https://github.com/bvaughn/react-virtualized. There is a x10 difference. I believe working on this would be a distraction for us.

In the future, I think that it would be great to explore the potential of an image component for Material-UI. Maybe something that comes with display transition, lazyload, error handling. Not a priority either, but I'm wondering about the potential 🤔.

@oliviertassinari oliviertassinari removed the waiting for 👍 Waiting for upvotes label Nov 30, 2019
@oliviertassinari oliviertassinari added new feature New feature or request and removed discussion labels Dec 11, 2020
@oliviertassinari oliviertassinari added the waiting for 👍 Waiting for upvotes label Dec 11, 2020
@oliviertassinari oliviertassinari changed the title [Intersection Observer]: Implementation of Intersection Observer API [useIntersectionObserver] Introduce new API Dec 11, 2020
@maerzhase
Copy link

IMHO if you decide on using a generic library (e.g. react-intersection-observer) material-ui itself should focus on providing a component-based API e.g. the Reveal component I propose in #23960 and not a hook-based API like useScrollTrigger, because it would obfuscate the usage of the library somehow.

@pranshuchittora
Copy link
Contributor Author

Hey, @oliviertassinari glad to see this happening.
The container component is an intuitive way for this feature. What about a custom hook as well, combining both could come with some great potential and enormous possibilities ✌️

@mbrookes
Copy link
Member

mbrookes commented Dec 14, 2020

With only one upvote in 18 months, this can be closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature New feature or request waiting for 👍 Waiting for upvotes
Projects
None yet
Development

No branches or pull requests

4 participants