【问题标题】:Infinite scrolling with React JS使用 React JS 无限滚动
【发布时间】:2014-02-09 21:33:30
【问题描述】:

我正在寻找使用 React 实现无限滚动的方法。我遇到了react-infinite-scroll 并发现它效率低下,因为它只是将节点添加到 DOM 而不会删除它们。是否有任何经过验证的 React 解决方案可以在 DOM 中添加、删除和维护恒定数量的节点。

这是jsfiddle 问题。 在这个问题中,我希望一次在 DOM 中只有 50 个元素。当用户上下滚动时,其他的应该被加载和删除。 我们已经开始使用 React 是因为它的优化算法。现在我找不到这个问题的解决方案。我遇到过airbnb infinite js。但它是用 Jquery 实现的。要使用这个 airbnb 无限滚动,我必须放松我不想做的 React 优化。

我要添加滚动的示例代码是(这里我正在加载所有项目。我的目标是一次只加载 50 个项目)

/** @jsx React.DOM */

var Hello = React.createClass({
    render: function() {
        return (<li>Hello {this.props.name}</li>);
    }
});

var HelloList = React.createClass({ 
     getInitialState: function() {                            
         var numbers =  [];
         for(var i=1;i<10000;i++){
             numbers.push(i);
         }
         return {data:numbers};
     },

    render: function(){
       var response =  this.state.data.map(function(contact){          
          return (<Hello name="World"></Hello>);
        });

        return (<ul>{response}</ul>)
    }
});

React.renderComponent(<HelloList/>, document.getElementById('content'));

寻求帮助...

【问题讨论】:

    标签: javascript html infinite-scroll reactjs


    【解决方案1】:

    基本上,在滚动时,您希望确定哪些元素可见,然后重新渲染以仅显示这些元素,顶部和底部有一个单独的间隔元素来表示屏幕外元素。

    Vjeux 在这里做了一个小提琴,你可以看看:jsfiddle

    滚动后执行

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

    然后渲染函数将只显示displayStart..displayEnd范围内的行。

    您可能还对ReactJS: Modeling Bi-Directional Infinite Scrolling感兴趣。

    【讨论】:

    • 这是一个很棒的技术...谢谢!但是,当每行的记录高度不同时,它会失败。我正在尝试解决这种情况。如果我让它工作,我会发布它。
    • @manalang 你有没有为每一行找到不同高度的解决方案?
    • 另一个要检查的项目是 infinity.js(以获取灵感)。如果您有动态高度元素,那么您可以创建“页面”的概念,它是视口中的一组元素。假设有 3 个元素,并且第三个元素超长并且延伸到页面之外。然后你可以说,“页面高度”是最大 3 个元素的大小。然后使用 smallest 元素高度构造虚拟节点。所以var count = pageHeight / minElementHeight。因此,您可能会构建 50 个元素,即使只渲染了 3 个,但这仍然会给您带来良好的性能。
    • 小提琴中没有出现任何内容。生成按钮出现,但没有其他内容。
    • @sophie-alpert :是否可以更新 jsfiddle ?我知道你会很忙,但如果你能更新它,它会让像我这样的人受益:D
    【解决方案2】:

    查看我们的 React 无限库:

    https://github.com/seatgeek/react-infinite

    2016 年 12 月更新

    实际上,我最近在很多项目中都使用了react-virtualized,发现它更好地涵盖了大多数用例。两个库都很好,这完全取决于您要查找的内容。例如,react-virtualized 支持通过名为 CellMeasurer 的 HOC 进行可变高度 JIT 测量,例如此处为 https://bvaughn.github.io/react-virtualized/#/components/CellMeasurer

    2018 年 11 月更新

    react-virtualized 中的许多经验已被移植到同一作者的更小、更快、更高效的 react-window 库中。

    【讨论】:

    • @jos:使用这个库。当 DOM 节点出现在视口中时,它将删除/附加它们。
    • 这个库只有在渲染前知道元素的高度时才有效。
    • @Druska,技术上是的,但是您也可以使用 useWindowAsScrollContainer 选项将窗口用作滚动容器。
    • react-infinite 库是否支持网格?
    【解决方案3】:
    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;
    

    【讨论】:

      猜你喜欢
      • 2018-07-03
      • 2015-04-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-02
      • 1970-01-01
      • 2016-01-26
      • 2021-11-22
      • 1970-01-01
      相关资源
      最近更新 更多