ReactJS:无限滚动不起作用



我正在尝试在我的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);
}

最新更新