Reactjs:Infinite 滚动不工作

Reactjs:Infinite Scroll not working

我正在尝试在我的网站中添加无限滚动 application.When 用户向下滚动页面,必须有一个 API 调用来加载现有 data.So 下的数据,这里的问题是当我到达网页底部时,没有调用 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;

以下应该有效。

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

这实际上只是一个未正确绑定 this 的模糊案例:以下行调用 handleOnScroll 使用 window 不是 InfiniteData 组件实例)为 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 调用)

正如 Daniel Thompson 所说,问题是您没有绑定它。详细说明:当 eventListener 调用函数 this 时,不会绑定到您的组件,而是绑定到 window

在事件监听器中绑定this可以解决代码不被调用的问题,但会产生新的问题。当您调用 handleOnScroll.bind(this) 时,会创建一个新函数,因此当您尝试注销它时,它不会注销。要使注册和注销都按预期工作,请保存该新功能并将其用于 register/unregister.

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);
}