我正在尝试在我的Web应用程序中添加无限滚动。当用户向下滚动页面时,必须有一个API调用来加载现有数据下方的数据。问题是当我到达网页的底部时,API并未被调用。
import React from "react";
import { Link } from 'react-router-dom';
import axios from 'axios';
class InfiniteData extends React.Component{
constructor(props){
super(props);
this.state={olddata: [],newData: [], requestSent: false}
}
componentDidMount(){
window.addEventListener('scroll', this.handleOnScroll);
this.doQuery();
}
componentWillUnmount() {
window.removeEventListener('scroll', this.handleOnScroll);
}
doQuery() {
console.log("indoquery");
axios.get("https://jsonplaceholder.typicode.com/posts")
.then( res=>
this.setState({
olddata: res.data,
newData: this.state.olddata.concat(this.state.olddata)
})
)
.catch(console.log("error"))
}
handleOnScroll(){
var scrollTop = (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;
var scrollHeight = (document.documentElement && document.documentElement.scrollHeight) || document.body.scrollHeight;
var clientHeight = document.documentElement.clientHeight || window.innerHeight;
var scrolledToBottom = Math.ceil(scrollTop + clientHeight) >= scrollHeight;
if (scrolledToBottom) {
console.log("At bottom");
// enumerate a slow query
setTimeout(this.doQuery, 2000);
}
}
render()
{
return (
<div>
<div className="data-container">
{this.state.newData && this.state.newData.map((dat,i)=>
<div key={i}>
{dat.body}
</div>
)}
</div>
</div>
);
}
}
export default InfiniteData;
这实际上只是一个晦涩的情况,即正确绑定this
:以下行使用window
调用handleOnScroll
( not infinitedata component instance实例(为this
:
window.addEventListener('scroll', this.handleOnScroll);
然后,您的setTimeout
调用正在尝试调用this.doQuery
,这是undefined
,因为window.doQuery
不存在。
如果您对EventListener正确绑定this
,则应该解决:在componentDidMount
中更改为window.addEventListener('scroll', this.handleOnScroll.bind(this));
,或在constructor
中添加以下行以保持整个木板的绑定:
this.handleOnScroll = this.handleOnScroll.bind(this)
注意:这不是您遇到的问题,但是在setState
呼叫中要小心 - 您是要使用newData: this.state.olddata.concat(res.data)
吗?(将res.data
传递到concat
调用(
以下应该有效。
import React from "react";
function doQuery() {
console.log("indoquery");
// Do something here
}
class InfiniteData extends React.Component{
constructor(props){
super(props);
this.state={olddata: [],newData: [], requestSent: false}
}
componentDidMount(){
window.addEventListener('scroll', this.handleOnScroll);
doQuery();
}
componentWillUnmount() {
window.removeEventListener('scroll', this.handleOnScroll);
}
handleOnScroll(){
// .....
if (scrolledToBottom) {
setTimeout(function () {doQuery()}, 2000);
}
}
render() {
return (
<div>
</div>
);
}
}
export default InfiniteData;
请注意,我已删除了一些代码,以使其紧凑,更容易让您了解问题所在的位置。基本上,修复程序是您定义doquery函数的地方以及如何通过该函数来settimeout
正如丹尼尔·汤普森(Daniel Thompson(所说的那样,问题是您不绑定它。详细说明:当EventListener调用功能时,this
不会绑定到您的组件,而是与window
绑定。
绑定this
在事件中,侦听器将解决未调用的代码问题,但会创建一个新问题。当您调用handleOnScroll.bind(this)
时,会创建一个新功能,因此,当您尝试取消注册时,它不会取消注册。要获得注册和未注册以按预期工作,请保存该新功能并使用它进行注册/取消注册。
constructor(props){
super(props);
// Need to bind 'this' to refer to component.
// This will create a new function which will have to be stored so it can be unregistered
this.scrollListener = this.handleOnScroll.bind(this);
this.state={olddata: [],newData: [], requestSent: false}
}
componentDidMount(){
window.addEventListener('scroll', this.scrollListener);
this.doQuery();
}
componentWillUnmount() {
window.removeEventListener('scroll', this.scrollListener);
}