React JS ile sonsuz kaydırma


91

React ile sonsuz kaydırmayı gerçekleştirmenin yollarını arıyorum. Ben rastlamak tepki sonsuz-scroll hem de verimsiz sadece DOM düğümleri ekler ve bunları kaldırmaz olarak bulundu. DOM'da sabit sayıda düğüm ekleyecek, kaldıracak ve koruyacak, React ile kanıtlanmış bir çözüm var mı?

İşte jsfiddle sorunu. Bu problemde, DOM'da bir seferde yalnızca 50 öğeye sahip olmak istiyorum. diğerleri kullanıcı yukarı ve aşağı kaydırdıkça yüklenmeli ve kaldırılmalıdır. Optimizasyon algoritmaları nedeniyle React'i kullanmaya başladık. Şimdi bu soruna çözüm bulamadım. Ben geldim airbnb sonsuz js . Ancak Jquery ile uygulanmaktadır. Bu airbnb sonsuz kaydırmayı kullanmak için, yapmak istemediğim React optimizasyonunu kaybetmem gerekiyor.

kaydırma eklemek istediğim örnek kod (burada tüm öğeleri yüklüyorum. Amacım bir seferde yalnızca 50 öğe yüklemek)

/** @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'));

Yardım istiyorum...

Yanıtlar:


58

Temel olarak kaydırırken, hangi öğelerin görünür olduğuna karar vermek ve ardından ekran dışı öğeleri temsil etmek için üstte ve altta tek bir boşluk öğesi olacak şekilde yalnızca bu öğeleri görüntülemek için yeniden oluşturmak istersiniz.

Vjeux burada bakabileceğiniz bir keman yaptı: jsfiddle .

Kaydırma üzerine yürütür

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

ve sonra render işlevi yalnızca aralıktaki satırları görüntüler displayStart..displayEnd.

Ayrıca ilginizi çekebilir ReactJS: Çift Yönlü Sonsuz Kaydırmayı Modelleme .


2
Bu harika bir teknik ... teşekkürler! Ancak, recordHeight her satır için farklı olduğunda başarısız olur. Bu durum için bir düzeltme deniyorum. Çalışmasını sağlarsam göndereceğim.
manalang

@manalang Her satır için farklı yükseklik için çözüm buldunuz mu?
istisna

1
Kontrol edilecek başka bir proje de infinity.js'dir (ilham almak için). Dinamik yükseklik öğeleriniz varsa, görüntü alanındaki bir dizi öğe olan "sayfa" konseptini oluşturabilirsiniz. Diyelim ki 3 öğe var ve üçüncü öğe süper uzun ve sayfadan uzanıyor. Daha sonra, "sayfa yüksekliği" nin en büyük 3 öğenin boyutu olduğunu söyleyebilirsiniz. Ardından en küçük eleman yüksekliğini kullanarak sanal düğümler oluşturun . Yani var count = pageHeight / minElementHeight. Dolayısıyla, yalnızca 3 tanesi işlenmiş olsa bile 50 öğe oluşturabilirsiniz, ancak bu yine de size iyi bir performans sağlayacaktır.
Lance Pollard

14
Keman içinde hiçbir şey görünmez. Oluştur düğmeleri görünür, ancak başka hiçbir şey görünmez.
44'te gök gürültüsü

3
@ sophie-alpert: jsfiddle'ı güncellemek mümkün mü? Meşgul olacağınızı biliyorum, ancak bunu güncelleyebilirseniz, benim gibi birçok kişiye fayda sağlar: D
John Samuel

26

React Infinite Kitaplığımıza göz atın:

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

Aralık 2016 güncellemesi

Aslında son zamanlarda birçok projemde react-sanallaştırılmış kullanıyorum ve kullanım durumlarının çoğunu çok daha iyi kapsadığını görüyorum . Her iki kütüphane de iyidir, tam olarak ne aradığınıza bağlıdır. Örneğin, react-sanallaştırılmış, bir HOC aracılığıyla değişken yükseklikte JIT ölçümünü destekler CellMeasurer, örneğin burada https://bvaughn.github.io/react-virtualized/#/components/CellMeasurer .

Kasım 2018 Güncellemesi

React-sanallaştırmadan alınan derslerin çoğu , aynı yazardan daha küçük, daha hızlı, daha verimli react-window kitaplığına aktarıldı .


@jos: bu kitaplığı kullanın. Görünüm alanında göründükleri şekilde DOM düğümlerini kaldırır / ekler.
wle8300

14
Bu kitaplık yalnızca, oluşturmadan önce öğelerinizin yüksekliğini biliyorsanız çalışır.
Druska

1
@Druska, Teknik olarak evet, ancak useWindowAsScrollContainer seçeneğini kullanarak pencereyi kaydırma konteyneri olarak da kullanabilirsiniz.
HussienK

React-infinite kütüphanesi ızgaraları destekliyor mu?
user1261710


1
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;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.