我试图在我的网络应用程序中添加无限滚动。当用户向下滚动页面时,必须有一个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;
答案 0 :(得分:4)
这实际上只是一个未正确绑定this
的模糊情况:以下行使用handleOnScroll
(不 InfiniteData组件实例)调用window
this
:
window.addEventListener('scroll', this.handleOnScroll);
然后,您的setTimeout
来电正试图致电this.doQuery
,undefined
,因为window.doQuery
不存在。
如果您为EventListener正确绑定this
,这应该可以解决:更改为window.addEventListener('scroll', this.handleOnScroll.bind(this));
中的componentDidMount
或在constructor
中添加以下行以保留它全面绑定:
this.handleOnScroll = this.handleOnScroll.bind(this)
注意:这不是您遇到的问题,但在setState
电话中要小心 - 您的意思是使用newData: this.state.olddata.concat(res.data)
吗? (将res.data
传递给concat
来电)
答案 1 :(得分:0)
以下应该工作。
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
的地方答案 2 :(得分:0)
正如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);
}