У меня есть прокручиваемый компонент, который может иметь прокручиваемых потомков или внуков.Я хочу ограничить обработчик 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 ().См. Реагирование на объединение событий для получения дополнительной информации.
Runnable Snippet, который воспроизводит этот случай.Откройте 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
выше, регулирование никогда не произойдет!Опять же, я «думаю» (возможно, я ошибаюсь), что это может быть связано с тем, что при каждой прокрутке создается новая функция, приводящая к новому дросселю, новому ожиданию… которое никогда не наступает.Я не вижу этого в журналах!
Вопрос: , Как я могу убедиться, что я вызываю газ при прокрутке, но все еще останавливаю следующие свитки в ожидании, от распространения к родителю