我试图让我的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只是一个索引,用于跟踪用户当前在页面上所使用的卡。
必须有一种更好的方法,我只是不知道从哪里开始。
答案 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>