每个div已滚动到视图和更新状态时触发事件

时间:2019-10-10 17:43:18

标签: javascript reactjs

我试图让我的React组件之一在每次子组件之一滚动到视图中时触发一个事件。为此,我将孩子的引用传递给父母,然后将窗口的位置与“ currentCard的”引用进行比较。一旦窗口到达currentCard的底部,它将在currentCard的状态上加1。问题是,当我setState发生得不够快时,滚动事件会触发多个setStates然后超出范围。这是我处理滚动的方式:

componentDidMount(){
    window.addEventListener('scroll', (e) => this.handleScroll(e))
}

handleScroll = (e) => {
    let { cardRefs, currentCard } = this.state;
    let currentCardPos = cardRefs[currentCard].current.getBoundingClientRect().height

    if ( window.pageYOffset >= currentCardPos ){
      console.log('bottom')
      this.setState(prevState => ({
        currentCard: prevState.currentCard + 1
      }))
    }
}

cardRefs是从子组件传递的一系列ref,而currentCard只是一个索引,用于跟踪用户当前在页面上所使用的卡。

必须有一种更好的方法,我只是不知道从哪里开始。

1 个答案:

答案 0 :(得分:0)

在您的情况下,您正在使用getBoundingClientRect().height,它将始终是一个常数。例如,如果将高度设置为500px,则始终返回500px。在window.offsetY超过500px之后,它会不断递增,直到超出范围。

相反,您可以尝试使用getBoundingClientRect().bottom。当该值变为负数时,表示它不在视口中,可以将状态设置为下一个元素。

下面添加了一个示例SO代码段。元素消失后,您可以向下滚动并在控制台中查看状态更新。希望这会有所帮助!

class App extends React.Component {
  state = { cardRefs: [], currentCard: 0 };
  myRef1 = React.createRef();
  myRef2 = React.createRef();
  myRef3 = React.createRef();

  componentDidMount() {
    window.addEventListener("scroll", this.handleScroll);
    this.setState({
      cardRefs: [this.myRef1, this.myRef2, this.myRef2]
    });
  }

  handleScroll = () => {
    let { cardRefs, currentCard } = this.state;
    if (cardRefs[currentCard].current.getBoundingClientRect().bottom < 0) {
      console.log("bottom");
      this.setState(prevState => {
        return {
          currentCard:
            currentCard + 1 >= cardRefs.length
              ? cardRefs.length - 1
              : currentCard + 1
        };
      });
    }
  };
  render() {
    console.log("Current Card", this.state.currentCard);
    return (
      <div>
        <div
          ref={this.myRef1}
          style={{ height: "500px", backgroundColor: "red" }}
        ></div>
        <div
          ref={this.myRef2}
          style={{ height: "500px", backgroundColor: "green" }}
        ></div>
        <div
          ref={this.myRef3}
          style={{ height: "500px", backgroundColor: "blue" }}
        ></div>
      </div>
    );
  }
}


ReactDOM.render(
    <App />,
  document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>