Reactjs:Infinite Scroll无效

时间:2018-02-06 14:47:48

标签: javascript reactjs api redux axios

我试图在我的网络应用程序中添加无限滚动。当用户向下滚动页面时,必须有一个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;

3 个答案:

答案 0 :(得分:4)

这实际上只是一个未正确绑定this的模糊情况:以下行使用handleOnScroll InfiniteData组件实例)调用window this

window.addEventListener('scroll', this.handleOnScroll);

然后,您的setTimeout来电正试图致电this.doQueryundefined,因为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);
}