import React, { Component } from 'react'; import InfiniteScroll from 'react-infinite-scroller'; const api = { baseUrl: '/joblist' }; class Jobs extends Component { constructor(props) { super(props); this.state = { listData: [], hasMoreItems: true, nextHref: null }; } fetchData(){ var self = this; var url = api.baseUrl; if(this.state.nextHref) { url = this.state.nextHref; } fetch(url) .then( (response) => { return response.json() }) .then( (json) => { var list = self.state.listData; json.data.map(data => { list.push(data); }); if(json.next_page_url != null) { self.setState({ nextHref: resp.next_page_url, listData: list }); } else { self.setState({ hasMoreItems: false }); } }) .catch(error => console.log('err ' + error)); } } componentDidMount() { this.fetchData(); } render() { const loader = <div className="loader">Loading ...</div>; let JobItems; if(this.state.listData){ JobItems = this.state.listData.map(Job => { return ( <tr> <td>{Job.job_number}</td> <td>{Job.title}</td> <td>{Job.description}</td> <td>{Job.status}</td> </tr> ); }); } return ( <div className="Jobs"> <div className="container"> <h2>Jobs List</h2> <InfiniteScroll pageStart={0} loadMore={this.fetchData.bind(this)} hasMore={this.state.hasMoreItems} loader={loader}> <table className="table table-bordered"> <thead> <tr> <th>Job Number</th> <th>Title</th> <th>Description</th> <th>Status</th> </tr> </thead> <tbody> {JobItems} </tbody> </table> </InfiniteScroll> </div> </div> ); } } export default Jobs;
的 使用React Js的无限滚动概念 强>
我们可以通过监听滚动事件来进行无限滚动工作。我们可以将事件监听器添加到父最大div甚至窗口对象。
看看下面的代码
render() { return ( <div className="vc" ref="iScroll" style={{ height: "420px", overflow: "auto" }} > <h2>Hurrah! My First React Infinite Scroll</h2> <ul> </ul> </div> ); }
上面的代码有一个简单的ul标签;在其中我们将绑定所提取的项目。这个标签被div包围,我们将在其上附加一个事件监听器来监听scroll事件。
我希望你知道这里使用的所有标签。阿伦 - 你呢?好吧,有些人可能不熟悉ref!因此,ref用于定义对除法(div)或任何其他html元素的引用。通过使用此引用,您可以在反应中保持该元素。我们给了引用一个名称“Scroll”,你可以使用this.refs.iScroll访问这个div。
确保div的高度小于主要显示项目的总高度,否则您将获得滚动条。您可以将高度设置为100%或使用窗口对象而不是我们的iScroll div来在窗口级别进行滚动。
现在让我们来谈谈看起来像这样的构造函数:
constructor(props) { super(props); this.state = { items: 10, loadingState: false }; }
这里的状态对象有两个属性; items和loadingState。这些项表示可以作为lis包含在ul部分中的可用项目数,并且loadingState用于显示文本加载...正在加载数据时。 由于我们只是提供一个演示,所以为什么使用数字作为项目。在实际应用中,您可能会在那里保存您的实际数据列表。
之后,您将创建一个将呈现所有项目的函数:
displayItems() { var items = []; for (var k = 0; k < this.state.items; k++) { items.push(<li key={k}>Item-VoidCanvas {k}</li>); } return items; }
此功能创建一个li列表并显示所有项目。再次,因为它是一个演示,我们正在使用数字显示。在实际应用程序中,您需要迭代items数组并显示它包含的值。
立即更新渲染功能:
render() { return ( <div className="vc" ref="iScroll" style={{ height: "200px", overflow: "auto" }} > <h2>Hurrah! My First React Infinite Scroll</h2> <ul> {this.displayItems()} </ul> {this.state.loadingState ? <p className="loading"> loading More Items.. </p> : ""} </div> ); }
是的,这只是一个显示少数lis的正常组件。它如何使它无限可滚动?希望你能记得我们之前使用过一个名为iScroll的引用,现在就开始行动了。
componentDidMount() { this.refs.iScroll.addEventListener("scroll", () => { if ( this.refs.iScroll.scrollTop + this.refs.iScroll.clientHeight >= this.refs.iScroll.scrollHeight ) { this.loadMoreItems(); } }); }
众所周知,react组件有一个函数componentDidMount(),当该组件的模板被渲染到DOM中时会自动调用它。我已经使用相同的函数添加事件监听器以滚动到我们的div iScroll。 元素的scrollTop属性将找到滚动位置,并使用clientHeight属性。 接下来,if条件将检查这两个属性的添加是否大于或等于滚动条高度。如果条件为true,则loadMoreItems函数将运行。
以下是该函数的外观:
loadMoreItems() { if(this.state.loadingState){ return; } this.setState({ loadingState: true }); // you may call ajax instead of setTimeout setTimeout(() => { this.setState({ items: this.state.items + 10, loadingState: false }); }, 1000); }
这很简单,首先将loadingState设置为true,然后显示加载div(如render函数所示)。接下来,调用setTimeout函数,这将使项目数增加10并再次使loadingState为false。 这里我们使用setTimeout的原因是生成时间延迟。在实际应用程序中,您可能会对服务器进行ajax调用,并且在解析之后,您将执行类似的操作,这是通过setTimeout的回调完成的。 完整的代码段在这里:
class Layout extends React.Component { constructor(props) { super(props); this.state = { items: 10, loadingState: false }; } componentDidMount() { this.refs.iScroll.addEventListener("scroll", () => { if (this.refs.iScroll.scrollTop + this.refs.iScroll.clientHeight >= this.refs.iScroll.scrollHeight - 20){ this.loadMoreItems(); } }); } displayItems() { var items = []; for (var i = 0; i < this.state.items; i++) { items.push(<li key={i}>Item {i}</li>); } return items; } loadMoreItems() { if(this.state.loadingState){ return; } this.setState({ loadingState: true }); setTimeout(() => { this.setState({ items: this.state.items + 10, loadingState: false }); }, 1000); } render() { return ( <div ref="iScroll" style={{ height: "200px", overflow: "auto" }}> <ul> {this.displayItems()} </ul> {this.state.loadingState ? <p className="loading"> loading More Items..</p> : ""} </div> ); } } ReactDOM.render(<Layout />, document.getElementById('example'));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <div id="example"></div>
基本上在滚动时,您想要确定哪些元素是可见的,然后重新渲染以仅显示那些元素,在顶部和底部使用单个间隔元素来表示屏幕外元素。
Vjeux 在这里做了一个小提琴你可以看一下:
http://jsfiddle.net/vjeux/KbWJ2/9/
滚动时执行
scrollState: function(scroll) { var visibleStart = Math.floor(scroll / this.state.recordHeight); var visibleEnd = Math.min(visibleStart + this.state.recordsPerBody, this.state.total - 1); var displayStart = Math.max(0, Math.floor(scroll / this.state.recordHeight) - this.state.recordsPerBody * 1.5); var displayEnd = Math.min(displayStart + 4 * this.state.recordsPerBody, this.state.total - 1); this.setState({ visibleStart: visibleStart, visibleEnd: visibleEnd, displayStart: displayStart, displayEnd: displayEnd, scroll: scroll }); },
然后render函数将只显示范围中的行 displayStart..displayEnd 。
displayStart..displayEnd
您也可能对。。。有兴趣 ReactJS:双向无限滚动建模 。
看看我们的React Infinite Library:
https://github.com/seatgeek/react-infinite
的 2016年12月更新 强>
我实际上一直在使用 反应虚拟化 我最近在很多项目中发现它覆盖了大多数用例,效果要好得多。两个库都很好,它取决于你正在寻找什么。例如,react-virtualized支持通过调用的HOC进行可变高度JIT测量 CellMeasurer ,例如这里 https://bvaughn.github.io/react-virtualized/#/components/CellMeasurer 。
CellMeasurer
的 2018年11月更新 强>
反应虚拟化的许多教训已经被移植到更小,更快,更高效的地方 反应窗 来自同一作者的图书馆。