【问题标题】:Reactjs:Infinite Scroll not workingReactjs:无限滚动不起作用
【发布时间】:2018-02-06 14:47:48
【问题描述】:

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

【问题讨论】:

    标签: javascript reactjs api redux axios


    【解决方案1】:

    这实际上只是一个未正确绑定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 提供了很好的描述性答案。正如您所提到的,在 setState 中使用 concat 是一种不好的方法,否则会导致进一步的问题,合并新数据的正确方法是什么与上一个状态数据?请帮助我。
    • @karthik concat 可能没问题,只是您调用了this.state.olddata.concat(this.state.olddata),这只是将旧数据加倍而不是添加新数据!我的猜测是您只需要一个处于状态 (this.state.data) 的 data 元素,然后将 setState 调用为 this.setState({ data: this.state.data.concat(res.data) })。如果您需要跟踪旧数据,您仍然可以这样做,但从您在此处发布的内容来看,您不需要它
    • 是的,我已将其更改为newData: this.state.newData.slice().concat(res)。它现在可以正常工作了
    【解决方案2】:

    以下应该可以工作。

    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

    【讨论】:

      【解决方案3】:

      正如 Daniel Thompson 所说,问题在于您没有绑定 this。详细说明:当 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);
      }
      

      【讨论】:

        猜你喜欢
        • 2013-02-17
        • 1970-01-01
        • 1970-01-01
        • 2014-03-14
        • 2013-07-05
        • 2018-10-22
        • 1970-01-01
        • 2020-03-09
        相关资源
        最近更新 更多