civiccc / react-waypoint

A React component to execute a function whenever you scroll to an element.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

An example with two columns scrollable?

kud opened this issue · comments

Do you think it could be possible to make an example with two columns scrollable?

This is my try but I don't get it

  • index.js
import styles from "./index.module.css"

import React from "react"
import PropTypes from "prop-types"
import Waypoint from "react-waypoint"
import randomColor from "randomcolor"

function getRandomInt(min, max) {
  min = Math.ceil(min)
  max = Math.floor(max)

  return Math.floor(Math.random() * (max - min)) + min
}

class Block extends React.Component {
  render() {
    return (
      <div id={this.props.id} ref={this.props.innerRef} style={{
        height: getRandomInt(200, 1200) + "px",
        backgroundColor: randomColor({ seed: this.props.i*10 }),
        fontWeight: "bold",
        fontSize: "20px",
        color: "white",
        padding: "20px",
        textShadow: "0px 0px 1px black",
        borderBottom: "4px dashed white",
        display: "block",
      }}>
        {this.props.id}
      </div>
    )
  }
}

Block.propTypes = {
  innerRef: PropTypes.func.isRequired,
  id: PropTypes.string.isRequired,
  i: PropTypes.any.isRequired,
}

const BlockWithRef = React.forwardRef((props, ref) => {
  return <Block innerRef={ref} {...props} />
})

class SandboxPage extends React.Component {
  handleEnterA = (el, props) => {
    console.log("A: ENTER", el)
  }

  handleLeaveA = (el, props) => {
    console.log("A: LEAVE", el)
  }

  handleEnterB = (el, props) => {
    console.log("B: ENTER", el)
  }

  handleLeaveB = (el, props) => {
    console.log("B: LEAVE", el)
  }

  render() {
    return (
      <div className={styles.main} id="main">
        <div className={styles.column} id="A">
          {Array.from({length: 31}, (_, el) => (
            <Waypoint
              key={`A-${el}`}
              onEnter={(props) => { this.handleEnterA(el, props) }}
              onLeave={(props) => { this.handleLeaveA(el, props) }}
              fireOnRapidScroll
              topOffset="100px"
            >
              <BlockWithRef id={`A-${el}`} i={el} />
            </Waypoint>
          ))}
        </div>

        <div className={styles.column} id="B">
          {Array.from({length: 31}, (_, el) => (
            <Waypoint
                key={`B-${el}`}
                onEnter={(props) => { this.handleEnterB(el, props) }}
                onLeave={(props) => { this.handleLeaveB(el, props) }}
                fireOnRapidScroll
            >
              <BlockWithRef id={`B-${el}`} i={el} />
            </Waypoint>
          ))}
        </div>
      </div>
    )
  }
}

export default SandboxPage
  • index.module.css
.main {
  display: grid;
  grid-template-columns: repeat(2, 1fr)
}

.column {
  overflow-y: scroll;
  height: 100vh;
}

Thank you

Can you describe more specifically what's not working? Is it that the waypoints aren't firing at all? Or perhaps firing at the wrong time?

I'd like to trigger enter and leave on each column, but nothing happens now.

kapture 2018-12-06 at 12 18 15

Each block should trigger "enter" and "leave" but nothing happens and I've tried to change the scrollableAncestor, it didn't fix it.

If you add the debug prop to the waypoints, the console log might contain some information that can help you resolve this.

I already did it but to be honest, no :(

What do you think I should check there?

By any chance, is there a conflict with css grid or flexbox?

This shouldn't be because of flexbox or css grid. In the debug output, I would check that the scrollable ancestor is set to the right elements (the .column divs).

My trouble is here and I don't know why yet:

.column {
/*   overflow-y: auto; */
/*   height: 100vh; */
}

as seen, disabled works. But I don't have my both scrolls, i've got a global scroll on the page.

Yeah I wanted to check the scrollableAncestor, the problem is I only see that in the debug:

image

and I don't get it. It makes me think it's "window" there and no .column but I'm not sure at all.

Sorry for the live debug. (that's why I wanted to create a chat, haha)

OH MY GOD. I understand now why you think the debug mode could help me.

On Chrome (canary) I don't have the same result, which there helps me, yes:

image

We've got a "bug" with Firefox (Nightly); either it's firefox which displays not enough, or it's the way you display the debug.

Oh god, it's worst. It's not about debugging, it's about how the scrollableAncestor is detected on chrome and firefox.

image

image

I don't get the same result on firefox and chrome, the element is "visible", not "auto".

For a reason I don't explain yet, firefox has some troubles there:

function () {
      function _findScrollableAncestor() {
        var _props = this.props,
            horizontal = _props.horizontal,
            scrollableAncestor = _props.scrollableAncestor;


        if (scrollableAncestor) {
          return resolveScrollableAncestorProp(scrollableAncestor);
        }

        var node = this._ref;

        while (node.parentNode) {
          node = node.parentNode;

          if (node === document.body) {
            // We've reached all the way to the root node.
            return window;
          }

          var style = window.getComputedStyle(node);
          var overflowDirec = horizontal ? style.getPropertyValue('overflow-x') : style.getPropertyValue('overflow-y');
          var overflow = overflowDirec || style.getPropertyValue('overflow');

          // right here, firefox thinks it's "visible" on the first instance of the loop, where chrome says "auto"

          if (overflow === 'auto' || overflow === 'scroll') {
            return node;
          }
        }

        // A scrollable ancestor element was not found, which means that we need to
        // do stuff on window.
        return window;
      }

      return _findScrollableAncestor;
    }()

And the weirdest thing is it works well there: https://jsfiddle.net/_kud/u76b40Lr/5/

I wonder if the styles are applied asynchronously some way? Do things change if you inject styles earlier somehow?

By the way, thanks for being so persistent here. I appreciate you trying to pin this down!

Thank you @trotzig your component is amazing, I use it all the time. However, here I have to understand why it doesn't work like I'd to.

My goal here is to have two synchronised scrolls depending on where you are on ONE scroll.

But to be fair I think this discussion should be in a chat. :)

And about your note, the weird thing is that I've got hot reload, and when hot reload runs (like when I save my file), my render runs once again and seems to make it work. So I really wonder if I don't have a problem with the lifecycle on React but it's still weird it only happens on Firefox for the moment.