简体   繁体   English

反应滚动事件不断触发

[英]React scroll event keeps on firing

I'm working on a react functional components project, wherein I've to increment scroll position programmatically when a user actually scrolls in a div.我正在开发一个反应功能组件项目,其中当用户实际滚动 div 时,我必须以编程方式增加滚动 position。

for example , I've a div with id testDiv & a user scrolled down a bit, now the scroll position is 100, so I want to programmatically increment it by 1 and make it 101.例如,我有一个 id testDiv的 div 并且用户向下滚动了一点,现在滚动 position 为 100,所以我想以编程方式将其递增 1 并使其变为 101。

Problem statement: The scroll position keeps on incrementing via onScroll handler, so the scrollbar only stops at the end of the element even if we scroll only once.问题陈述:滚动 position 通过onScroll处理程序不断增加,因此即使我们只滚动一次,滚动条也只会在元素的末尾停止。

Expected behaviour: Scroll position should be incremented only once by the onScroll handler if we scroll once on the UI.预期行为:如果我们在 UI 上滚动一次,滚动 position 应该只由onScroll处理程序增加一次。

What I tried: (dummy code for the reproduction purpose)我尝试了什么:(用于复制目的的虚拟代码)

import React, { useCallback } from "react";
import ReactDOM from "react-dom";
    
const App = (props) => {
  const onScroll = useCallback((event) => {
    const section = document.querySelector('#testDiv');
    // **The problem is here, scrollTop keeps on incrementing even if we scrolled only once**
    if (section) section.scrollTop = event.scrollTop + 1;
  }, []);
  
  return (
    <div id="testDiv" onScroll={onScroll} style={{ height: "500px", overflowY: "scroll" }}>
      <div>test</div>
      <div className="forceOverflow" style={{height: 500 * 25}}></div>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));

What you're looking for is throttling or debouncing the function.您正在寻找的是对 function 进行节流或去抖动。 It keeps on incrementing because with every bit of scroll, onScroll is being called.它不断增加,因为随着每一位滚动, onScroll被调用。

There are many ways to throttle functions in react but I like to use debounce from lodash.有很多方法可以限制 react 中的函数,但我喜欢使用 lodash 的 debounce。 If I remember correctly it was about 1.5kb gzipped.如果我没记错的话,它压缩后的大小约为 1.5kb。

I made you a sandbox .我给你做了一个沙盒 And here is the code:这是代码:

import React, { useCallback } from "react";
import _debounce from "lodash/debounce";

export const App = (props) => {
  let debouncedOnScroll = useCallback(
    _debounce(() => {
      // YOUR CODE HERE
      console.log("CHECK THE CONSOLE TO SEE HOW MANY TIMES IT'S GETTING CALLED");
    }, 150), []); // Wait 150ms to see if I'm being called again, if I got called before 150ms, don't run me!

  return (
    <div
      id="testDiv"
      onScroll={debouncedOnScroll}
      style={{ height: "500px", overflowY: "scroll" }}
    >
      <div>test</div>
      <div className="forceOverflow" style={{ height: 500 * 25 }}></div>
    </div>
  );
};

By the way, use useRef API instead of document.querySelector .顺便说一句,使用useRef API 而不是document.querySelector This query selector is getting called with every scroll and it's not the lightest weight on the client computer.每次滚动都会调用此查询选择器,它不是客户端计算机上最轻的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM