fkhadra / react-on-screen

Check if a react component in the viewport
https://fkhadra.github.io/react-on-screen/
MIT License
405 stars 50 forks source link

How about offset prop? #1

Closed 0is1 closed 7 years ago

0is1 commented 7 years ago

Hi, and thanks for this nice visibility tracker component!

I'm using this for lazy loading data (images at the moment) from API but there's one pitfall: API call is firing only just when you scroll down to the img-element and you will see image loader :)

So it would be nice if you could add offset to TrackVisibility-component, like:

<TrackVisibility offset={1000}><Image {...otherProps} id={imageId} /></TrackVisibility>

In Image-component I have logic like (this is simplified):

componentDidMount() {
        const {id, isVisible} = this.props;
        if(isVisible){
            fetchImage(id);
        }
    },

So then in node_modules/react-on-screen/lib/TrackVisibility.js:

const propTypes = {
  once: PropTypes.bool,
  throttleInterval(props, propName, component) {
    const currentProp = props[propName];
    if (!Number.isInteger(currentProp) || currentProp < 0) {
      return new Error(`The ${propName} prop you provided to ${component} is not a valid integer >= 0.`);
    }
  },
  children: PropTypes.oneOfType([
    PropTypes.element,
    PropTypes.arrayOf(PropTypes.element)
  ]),
  style: PropTypes.object,
  className: PropTypes.string,
  offset: PropTypes.number,
};

const defaultProps = {
  once: false,
  throttleInterval: 150,
  style: null,
  className: null,
  offset: 0
};

-------------

isComponentVisible() {
    const rect = this.nodeRef.getBoundingClientRect();
    const html = document.documentElement;
    const offset = this.props.offset;
    if (
      rect.top >= 0 &&
      rect.left >= 0 &&
      rect.bottom <= (window.innerHeight + offset || html.clientHeight + offset) &&
      rect.right <= (window.innerWidth + offset || html.clientWidth + offset)
    ) {
      this.props.once && this.removeListener();
      !this.state.isVisible && this.setState({ isVisible: true });
    } else {
      this.state.isVisible && this.setState({ isVisible: false });
    }
  }

This way it would be possible to load the data from API before user scrolls down to the element. What do you think about the idea?

fkhadra commented 7 years ago

Hello,

You're welcome ! Being able to set the offset make sense in your case. This can probably be used for others things.

Using the component for lazy loading is definitely a good idea. I don't know why I didn't think about that use case 😁.

I must add a sample with lazy loading. I can plan a new release today. Maybe you would like to work on it ?

0is1 commented 7 years ago

Yeah, nice! Do you wish that I make PR for this?

fkhadra commented 7 years ago

Of course, lets do this 😄