如何阻止节流的卷轴传播到父级?

时间:2019-06-25 14:29:07

标签: reactjs event-handling throttling

我有Scrollable组件,可能有可滚动的子代或大子代。我想限制两个组件中的onScroll处理程序,但也要防止子级onScroll事件传播到父级。

我的尝试


import React from 'react;
import throttle from 'lodash.throttle'

/*
This component stops the scroll from propagting to the parent
But does not throttle, calls handleScroll way too many times
*/
const UnthrottledSubPage = () => {
  const handleScroll = event => {
    event.stopPropagation();
    console.count('? SubPage: scrolled: ');
    console.log(event);
  };
  return (<div onScroll={handleScroll}>Sub Page</div>);
};
/*
This component throttles the scroll alright...but I have no way 
of stopping the scroll event from propagating to a scrollable parent
or grand parent.
*/
const ThrottledSubPageA = () => {
  const handleScroll = event => {
    event.stopPropagation(); // lineA: Called too late.
    console.count('? SubPage: scrolled: ');
    console.log(event);
  };
  return (<div onScroll={throttle(handleScroll, 1000)}>Sub Page</div>);
};

我“怀疑”,这种方法有时在ThrottledSubPageA的油门正在等待时,没有调用handleScroll停止传播,而是调用了父级滚动,或者在已经合并时调用了父级滚动。导致此警告。

  

警告:出于性能原因,此合成事件被重用。如果   您看到的是,您正在访问方法stopPropagation   已发布/无效的合成事件。这是一项无操作功能。如果你   必须保留原始的合成事件,使用event.persist()。   有关更多信息,请参见React event-pooling

可运行的代码段,重现了这种情况。打开DevTools作为日志

// Scrollable Component, called within a Scrollable Grand Parent (App).
const SubPage = () => {
  const handleScroll = event => {
    event.stopPropagation();
    console.count('? SubPage: scrolled: ');
    console.log(event);
  };
  return (
    <div
      className="subpage"
      style={{ height: '200px' }}
      onScroll={throttle(handleScroll, 1000)}
    >
      <h1>Sub Page</h1>
      {/* Lengthy Scrollble Content */}
      <div className="content">Content</div>
    </div>
  );
};

const MainPage = props => {
  const { height } = props;
  return (
    <div className="page" style={{ height }}>
      <h1>Main Page</h1>
      <SubPage />
    </div>
  );
};

// Scrollable Component, that has a Scrollable Grand Child.
const App = () => {
  const handleScroll = event => {
    console.count('? App: scrolled: ');
    console.log(event);
  };

  return (
    <section className="app" onScroll={throttle(handleScroll, 1000)}>
      <MainPage height="200vh" />
      <footer>Footer</footer>
    </section>
  );
};

ReactDOM.render(<App />, document.getElementById('container'));
/* Styles: Mostly Irrelevant to the question */

body {
  padding: 0;
  margin: 0;
  overflow: hidden;
  height: 100vh;
}

.app {
  background: #ddd;
  width: 100%;
  height: 100vh;
  overflow-y: scroll;
  color: #2b2b2b;
  padding: 1rem;
}

.page,
.subpage {
  background: aquamarine;
  border: solid 1px red;
  padding: 2rem;
}

.subpage {
  border: solid 1px black;
  background: white;
  overflow-y: scroll;
}

.content {
  height: 200vh;
  background: yellow;
}

footer {
  background: black;
  color: white;
  display: block;
  width: 100%;
  padding: 1rem;
}
<div id="container"></div>

<script src="https://cdn.jsdelivr.net/npm/lodash.throttle@4.1.1/index.min.js"></script>
<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>


/*
This component doesn't throttle at all...and behaves like UnthrottledSubPage,
and whatever is within the throttle block is never called.
*/
const ThrottledSubPageB = () => {
  const handleScroll = event => {
    event.stopPropagation(); // lineA: Called alright.
    throttle(()=> {
      /* This block is never reached...*/
      console.count('? SubPage: scrolled: ');
      console.log(event);
    }, 1000);
  };
  return (<div onScroll={handleScroll)}>Sub Page</div>);
};

如果我移动油门来完成昂贵的滚动任务,例如上面的ThrottledSubPageB,则永远不会发生节流!再次,我“认为”(我可能是错误的),这可能是因为在每个滚动上创建了一个新函数,从而导致了新的油门,新的等待……这永远不会发生。我在日志中看不到它!

问题:,如何确保在滚动时调用油门,但仍然停止等待中的下一个滚动,使其传播到父级?

0 个答案:

没有答案