react-waypoint icon indicating copy to clipboard operation
react-waypoint copied to clipboard

Page loaded below waypoint

Open btmdave opened this issue 7 years ago • 9 comments

Is there a way to detect if the page has been loaded below a waypoint? Basically let's say you have a waypoint that you reach as you scroll down. This triggers onEnter and onLeave, however if you have a page where you start below the waypoint, these won't get triggered. Is there a way to detect the current scroll position relative to the waypoint?

btmdave avatar May 11 '18 16:05 btmdave

+1 to this—

onEnter fires on mounted if the element is visible during mount. Symmetrically it would make sense if onLeave did also fired if the component is not visible during mount.

dzucconi avatar May 18 '18 15:05 dzucconi

For now I'm just doing something like

componentDidMount() {
  if (!elVisible(this.targetEl)) {
    this.handleLeave();
  }
}

Where targetEl is a ref to the element I want the waypoint on and elVisible looks something like:

const elVisible = (el) => {
  const rect = el.getBoundingClientRect();

  return (
    rect.top >= 0 &&
    rect.left >= 0 &&
    rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
    rect.right <= (window.innerWidth || document.documentElement.clientWidth)
  );
};

I dislike this a great deal.

dzucconi avatar May 21 '18 16:05 dzucconi

Would you like to push that as a PR so that others can benefit? I'm thinking this could be an onLoad event where we pass in currentPosition (just like for onEnter and onLeave).

trotzig avatar May 22 '18 06:05 trotzig

Yeah, I'll take a look and try to open a PR.

dzucconi avatar May 23 '18 21:05 dzucconi

Hey @dzucconi any luck with this so far? No rush, just checking in

MatthewHerbst avatar Jun 07 '18 18:06 MatthewHerbst

Hey @MatthewHerbst

Running the test suite:

$ npm test

> [email protected] pretest .../react-waypoint
> npm run --silent lint


> [email protected] test .../react-waypoint
> npm run testonly


> [email protected] testonly .../react-waypoint
> karma start --single-run

INFO [karma]: Karma v1.7.1 server started at http://0.0.0.0:9876/
INFO [launcher]: Launching browser Chrome with unlimited concurrency
INFO [launcher]: Starting browser Chrome
INFO [Chrome 67.0.3396 (Mac OS X 10.13.4)]: Connected on socket tqIhOHPrJiveR0sPAAAA with id 49572015
ERROR: 'The above error occurred in the <Waypoint> component:
    in Waypoint
    in div

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://fb.me/react-error-boundaries to learn more about error boundaries.'
Chrome 67.0.3396 (Mac OS X 10.13.4): Executed 121 of 121 SUCCESS (0.404 secs / 0.368 secs)

I'm getting an error but then also it says 121 succeeded?

dzucconi avatar Jun 09 '18 18:06 dzucconi

@dzucconi I traced that log down to this test case: https://github.com/brigade/react-waypoint/blob/68d1948b26509941ec601057d1df989bb68366de/test/waypoint_test.jsx#L874

I've pushed a PR addressing the confusion around the error message here: https://github.com/brigade/react-waypoint/pull/255. You can safely ignore the error log.

trotzig avatar Jun 10 '18 07:06 trotzig

I think maybe I'm seeing why this behavior doesn't exist: executing a bunch of onExit callbacks at once when the page loads winds up tanking the performance test.

I'm wondering if maybe a better approach is to opt in with a separate set of props: onInitialRenderBelow / onInitialRenderAbove or something? (Which admittedly is ugly) Or I might be just missing something here.

dzucconi avatar Jun 18 '18 15:06 dzucconi

componentDidMount solutions leave a window of time (1/3 to 1/2 second in my testing) between the component mount and Waypoint's resize handlers. If someone scrolls during that time, your app state will still be out of sync.

Although onLeave doesn't get called on initial render, onPositionChange does. As a workaround, you can take advantage of that. This code causes onEnter and onLeave to mirror each other, and avoids fighting with the setTimeout inside react-waypoint.

import ReactWaypoint from "react-waypoint";

class Waypoint extends Component {
  render() {
    const { onLeave, onPositionChange } = this.props;
    return (
      <ReactWaypoint
        {...this.props}
        onPositionChange={position => {
          // In the case where the page is already scrolled down at the point when
          // the waypoint initializes, handle a "no previous, current above/below" by
          // calling onLeave with the position.
          //
          // See: https://github.com/brigade/react-waypoint/issues/253
          if (
            typeof position.previousPosition === "undefined" &&
            position.currentPosition !== ReactWaypoint.inside &&
            onLeave
          ) {
            return onLeave(position);
          }
          onPositionChange && onPositionChange(position);
        }}
        onLeave={onLeave}
      />
    );
  }
}

threehams avatar Aug 06 '18 19:08 threehams